Compare commits

..

10 Commits

Author SHA1 Message Date
Philipp Crocoll
832d3b3a95 1.05d release for nonet 2018-06-23 09:07:47 +02:00
Philipp Crocoll
37867634cd Merge branch 'master' into nonet
Conflicts:
	src/keepass2android/Properties/AndroidManifest_nonet.xml
2018-06-18 13:08:07 +02:00
Philipp Crocoll
d9713f8e18 switch to using Release build type instead of ReleaseNoNet (separation no longer required because a custom branch exists for the offline variant) 2018-02-28 06:06:26 +01:00
Philipp Crocoll
c583b58cb9 adjust manifest version for 1.04b release 2018-02-27 06:06:35 +01:00
Philipp Crocoll
bfeaf5dbf5 Merge branch '1.04' into nonet
Conflicts:
	src/keepass2android/Properties/AndroidManifest_nonet.xml
2018-02-21 05:58:01 +01:00
Philipp Crocoll
0907fa5685 manifest for 1.03-nonet release 2017-12-02 15:30:04 +01:00
Philipp Crocoll
ff8dc76c75 Merge branch 'master' into nonet
Conflicts:
	docs/README.md
2017-12-02 14:25:37 +01:00
Philipp Crocoll
0b09e2790f remove online file storages from project file 2017-10-25 06:49:02 +02:00
Philipp Crocoll
781350aa5f manifest for 1.02 release 2017-10-25 06:24:01 +02:00
Philipp Crocoll
9716130336 remove references to libraries only required for online build, adjust build script and README 2017-10-25 06:23:53 +02:00
1102 changed files with 19991 additions and 67670 deletions

11
.gitignore vendored
View File

@@ -160,14 +160,3 @@ src/java/Keepass2AndroidPluginSDK2/build/generated/mockable-Google-Inc.-Google-A
/src/.vs /src/.vs
/src/JavaFileStorageBindings/Jars/JavaFileStorage-release.aar /src/JavaFileStorageBindings/Jars/JavaFileStorage-release.aar
/src/PluginSdkBinding/Jars/app-debug.aar /src/PluginSdkBinding/Jars/app-debug.aar
/src/java/KP2AKdbLibrary/libs/arm64-v8a/libfinal-key.so
/src/java/KP2AKdbLibrary/libs/x86_64/libfinal-key.so
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs/arm64-v8a/libkp2akeyboard_jni.so
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs/armeabi-v7a/libkp2akeyboard_jni.so
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs/x86/libkp2akeyboard_jni.so
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs/x86_64/libkp2akeyboard_jni.so
/src/java/KP2AKdbLibrary/app/build
/src/java/KP2ASoftkeyboard_AS/app/.cxx
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs
/src/java/KP2AKdbLibrary/app/.cxx
/src/ActionViewFilterTest

6
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "src/SamsungPass"] [submodule "src/SamsungPass"]
path = src/SamsungPass path = src/SamsungPass
url = https://github.com/PhilippC/Xamarin-Samsung-Pass.git url = https://github.com/PhilippC/Xamarin-Samsung-Pass.git
[submodule "src/java/argon2/phc-winner-argon2"] [submodule "src/netftpandroid"]
path = src/java/argon2/phc-winner-argon2 path = src/netftpandroid
url = https://github.com/P-H-C/phc-winner-argon2 url = https://github.com/PhilippC/netftpandroid.git

View File

@@ -1,34 +0,0 @@
files:
- source: src/keepass2android/Resources/values/strings.xml
translation: >-
/src/keepass2android/Resources/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'
languages_mapping:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR
- source: src/java/android-filechooser-AS/app/src/main/res/values/strings.xml
translation: >-
/src/java/android-filechooser-AS/app/src/main/res/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'
languages_mapping:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR
- source: src/java/KP2ASoftkeyboard_AS/app/src/main/res/values/strings.xml
translation: >-
/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'
languages_mapping:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR

View File

@@ -7,12 +7,11 @@ If you think something is missing in the documentation, please create an issue a
If you store important information using Keepass2Android, you should know a little bit about what's going on: If you store important information using Keepass2Android, you should know a little bit about what's going on:
* Keepass2Android stores your password in an encrypted file. It is *your responsibility* to backup this file regularly and safely. * Keepass2Android stores your password in an encrypted file. It is *your responsibility* to backup this file regularly and safely.
* There is no way for anyone, including the app's author, to access the information stored in your password database without * There is no way for anyone, including the app's author, to access the information stored in your password database without
* having the database file ** having the database file
* knowing the master password (and additional second factor if you chose one) ** knowing the master password (and additional second factor if you chose one)
This means that **if you forget the master password, your database is lost**! So make sure you remember the password and retain any second factor method (if one is used). This means that **if you forget the master password, your database is lost**! So make sure you remember the password. You might also want to think about:
* You might also want to think about: ** What happens if I have an accident? Should any trusted person be able to access my database?
* What happens if I have an accident? Should any trusted person be able to access my database? ** What happens if my phone gets lost or stolen? Do I know how to recover my database from a backup or the cloud?
* What happens if my phone gets lost or stolen? Do I know how to recover my database from a backup or the cloud?
# Getting started # Getting started
@@ -28,14 +27,14 @@ Select "Create new database" from the start screen. Tap the integrated help icon
## Getting passwords into password fields ## Getting passwords into password fields
There are many ways how to enter the passwords from your database in the corresponding fields. By default, the clipboard as well as the KP2A keyboard are activated in the settings: There are many ways how to enter the passwords from your database in the corresponding fields. By default, the clipboard as well as the KP2A keyboard are activated in the settings:
* The KP2A keyboard is the recommended way because it's safe against clipboard loggers: Whenever you select an entry, the KP2A keyboard notification will appear in the notification bar. Click it to activate the keyboard. (The first time you do this, you are required to enable the keyboard in the system settings. This must be done by the user for Android security reasons.) As soon as it's activated, you can tap a field where you want to enter data from the selected entry. The KP2A keyboard will come up. Click the KP2A key (on the bottom left) to select whether you want to enter Username/password etc. When you're done, click the Keyboard key (next to the KP2A key) to switch back to your favorite keyboard. * The KP2A keyboard is the recommended way because it's safe against clipboard loggers: Whenever you select an entry, the KP2A keyboard notification will appear in the notification bar. Click it to activate the keyboard. (The first time you do this, you are required to enable the keyboard in the system settings. This must be done by the user for Android security reasons.) As soon as it's activated, you can tap a field where you want to enter data from the selected entry. The KP2A keyboard will come up. Click the KP2A key (on the bottom left) to select whether you want to enter Username/password etc. When you're done, click the Keyboard key (next to the KP2A key) to switch back to your favorite keyboard.
* You can enable the Keepass2Android Autofill service in the system's Autofill settings (Android 8+) which allows to fill data using Android's accessibility system. This works with many apps including Firefox browser but is not supported for Chrome (when writing this). * You can enable the Keepass2Android Autofill service in the system's accessibility settings which allows to fill data using Android's accessibility system. This works with many apps including Chrome browser but is not supported for Firefox on Android.
* The clipboard based approach can be used as well: Pull the notification bar down and select "Copy username/password to clipboard". Then long-tap the field where you want to paste the data. A small "paste" button should come up. Note, however, that information in the clipboard can be monitored by all apps on your device and clearing the clipboard is not always possible. * The clipboard based approach can be used as well: Pull the notification bar down and select "Copy username/password to clipboard". Then long-tap the field where you want to paste the data. A small "paste" button should come up. Note, however, that information in the clipboard can be monitored by all apps on your device.
These options can be used in different workflows: These options can be used in different workflows:
### Browser-based workflow ### Browser-based workflow
If you are browsing the web and need to enter crendentials for a webpage, a simple and powerful workflow is to use the "Share URL" option from the browser's menu. Then select Keepass2Android (or KP2A Offline). Open your database (if it's not already opened) and select the entry you want to enter (if KP2A did not already select the appropriate entry). Use the built-in keyboard or the clipboard to enter the password. If you are browsing the web and need to enter crendentials for a webpage, a simple and powerful workflow is to use the "Share URL" option from the browser's menu. Then select Keepass2Android (or KP2A Offline). Open your database (if it's not already opened) and select the entry you want to enter (if KP2A did not already select the appropriate entry). Use the built-in keyboard or the clipboard to enter the password.
### Autofill service based workflow ### Autofill service based workflow
If you have enabled the autofill service and open a (supported) app with a password field, a dropdown appears. Select "Fill with Keepass2Android" to select the appropriate entry. When you return to the app, the password and user field should be filled already. If you have enabled the autofill service and open a (supported) app with a password field, a notification appears in the notification bar. Select this notification to select the appropriate entry. When you return to the app, the password and user field should be filled already.
### KP2A based workflow for websites ### KP2A based workflow for websites
Open KP2A, open your database, select your entry (in this step, the notification bar items should show up already). Now click the URL link of the entry to open a browser window with the website. Use one of the methods described above to enter the credentials. Open KP2A, open your database, select your entry (in this step, the notification bar items should show up already). Now click the URL link of the entry to open a browser window with the website. Use one of the methods described above to enter the credentials.
### KP2A Keyboard based workflow ### KP2A Keyboard based workflow
@@ -70,51 +69,16 @@ Please see the [Advanced usage of the Keepass2Android keyboard](Advanced-usage-o
# FAQ # FAQ
## Should I use the KP2A keyboard for entering passwords? * Should I use the KP2A keyboard for entering passwords?
The KP2A keyboard is meant to quickly "paste" or "type" values from your database to any text fields by using the KP2A icon. The QUERTY keyboard is just for convenience (if you just have the KP2A keyboard activated and need to enter a few letters). However, every other (trustworthy) keyboard is ok as well to enter sensitive information: Keyboard's aren't unsafe in Android. Only the clipboard is. Thus, the KP2A keyboard allows to get information out of the database without using the clipboard. The KP2A keyboard is meant to quickly "paste" or "type" values from your database to any text fields by using the KP2A icon. The QUERTY keyboard is just for convenience (if you just have the KP2A keyboard activated and need to enter a few letters). However, every other (trustworthy) keyboard is ok as well to enter sensitive information: Keyboard's aren't unsafe in Android. Only the clipboard is. Thus, the KP2A keyboard allows to get information out of the database without using the clipboard.
**You can use any keyboard when you enter the main database password** **You can use any keyboard when you enter the main database password**
## Is it safe to store my kdbx file in the cloud? * Is it safe to store my kdbx file in the cloud?
While it may happen that someone gets access to your kdbx file in the cloud, there is still no need to worry: the purpose of encryption is to protect the data even in case someone gets the kdbx file! As long as you are using a safe master key, you're safe! [Key files](https://keepass.info/help/base/keys.html#keyfiles) can help with securing the database even more. While it may happen that someone gets access to your kdbx file in the cloud, there is still no need to worry: the purpose of encryption is to protect the data even in case someone gets the kdbx file! As long as you are using a safe master key, you're safe!
## Doesn't Keepass2Android create automatic backups? * Why is Keepass2Android so big?
Yes and no. Yes: Keepass2Android stores the last successfully opened file as a read-only backup locally on the phone (unless you disable this is in the settings). This should make sure that even if the file gets destroyed during a save operation or gets deleted by accident, you should always have a version that can be opened. (Don't mix this up with the internal file cache which is not meant as a backup and can easily be overwritten even with a corrupt file. This internal file cache is meant for providing writable access even when the original file is not reachable, e.g. when you're offline.)
No: The local backup has two shortcomings: It is only one backup and does not allow to revert to older versions. So if you deleted an entry from the database, it might be deleted in the local backup soon as well. The even more important shortcoming is that it is just a local backup. It won't help when your phone gets lost or broken. Please create additional backups on seperate storage!
## How do I backup the database?
If you have stored your database on the cloud, you might rely on your cloud storage providers backups. Make sure they allow you to revert to older revisions in case the file gets corrupted for some reason.
If you are working with a local database file, make sure you create regular backups. I suggest you have an aumotated mechanism, e.g. with FolderSync (Lite) which can copy local files from your device to other locations, e.g. your PC in a local network. You can also use USB or tools like MyPhoneExploror to transfer data to your PC. Or, you use a removable storage like an SD card which you keep in a safe place after making the backup.
In all cases, you need to verify that your backup is readable! It's even best to test this on another device (e.g. a PC), so you simulate the case that you may lose your phone.
## I can open my database with fingerprint, but don't remember my master password!
It's time for action! As soon as possible, select Settings - Database - Export and choose unencrypted XML (don't put this on the cloud but on a local file). Transfer this file to a PC and import it to a new kdbx file, e.g. with Keepass2. Choose a new master password and make sure you don't forget this password!
## How can I transfer data from one device to another?
* If you are about to get a new Android device, you should make sure you're not losing your passwords in the transition! The first thing you need to make sure is that you can access your .kdbx file (which stores the passwords) on the new device. If it is already stored in the cloud, you only need to make sure you know how to setup the cloud storage on the new device (it might require a password, so make sure you have access to that!).
* If the .kdbx-file is stored locally on the old device, make sure you have an up-to-date backup (see above). You can then transfer that backup copy to the new device. (Note: transferring via USB causes data corruption in some cases, use MyPhoneExplorer or similar tools to be sure this does not happen.)
* If you are securing your password database with a keyfile, also transfer this key file to the new device.
* If you are opening your database with a fingerprint, make sure you also know the master password because fingerprint will not be available immediately on the new device.
## Why is Keepass2Android's apk so big?
Please see [Keepass2Android Apk](Keepass2Android-Apk.md) for more information. Please see [Keepass2Android Apk](Keepass2Android-Apk.md) for more information.
## I get a message "File is trashed" when reading or writing a file on Google Drive
This happens because ocaml-fuse (I guess you are on Linux  and use that) moves files to trash and then creates a new one instead of correctly updating the file on Google Drive (each file has a unique ID which Keepass2Android uses). Fortunately, this was fixed: https://github.com/astrada/google-drive-ocamlfuse/issues/494After activating this option, please select "Change database" in KP2A, tap ,"Open file" and browse to the file on Google Drive again. After that, the message should no longer pop up.
## I get a message "The name must not be empty: null" when opening from Google Drive
Please follow these steps:
* select "Change database" on the password screen, then "Open database" and browse to your file again
* go to Android app settings and disable all permissions for the KP2A app. Then try again to open the database file.
* reboot the device
(Before running the following steps, make sure you don't have local changes in your database which have not been synchronized with Google Drive (this can happen if you worked offline). If you have, please open the database from the local cache and go to settings - database settings - export database and make a backup copy of the data.)
* clear KP2A's app cache in the Android settings
* uninstall & reinstall
One of these has helped all users so far, but unfortunately it's not totally clear to me why different steps are required (or nothing for most users).
# For developers # For developers
If you are interested in adding new features, you have two options: If you are interested in adding new features, you have two options:
Either your features can be implemented as a plug-in. Please see [How to create a plug-in?](How-to-create-a-plug-in_.md) for more information. Or you add the features directly in the source code of the projects and create a pull request. Either your features can be implemented as a plug-in. Please see [How to create a plug-in?](How-to-create-a-plug-in_.md) for more information. Or you add the features directly in the source code of the projects and create a pull request.

View File

@@ -54,7 +54,7 @@ Please also add a few strings in your resource files (e.g. strings.xml) with the
These strings will be displayed to the user when KP2A asks if access should be granted. These strings will be displayed to the user when KP2A asks if access should be granted.
## Modifying the entry view ## Modifying the entry view
You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https://play.google.com/store/apps/details?id=keepass2android.plugin.qr)). You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https___play.google.com_store_apps_details_id=keepass2android.plugin.qr)).
In addition, it is even possible to add new fields or modify existing fields. Please see the sample plugin "PluginA" in the KP2A repository for a simple example on how to do this: In addition, it is even possible to add new fields or modify existing fields. Please see the sample plugin "PluginA" in the KP2A repository for a simple example on how to do this:
[https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java](https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java) [https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java](https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java)

View File

@@ -4,28 +4,28 @@
on how to set up a Keepass 2 database with Yubikey/OTP protection.<br> on how to set up a Keepass 2 database with Yubikey/OTP protection.<br>
<br> <br>
After successful setup you should have the database file, e.g. yubi.kdbx, and the OTP auxiliary file, e.g. yubi.otp.xml, both in the same folder.<br> After successful setup you should have the database file, e.g. yubi.kdbx, and the OTP auxiliary file, e.g. yubi.otp.xml, both in the same folder.<br>
<a href="How to use Keepass2Android with YubiKey NEO_OTPAuxFile_2.png"><img title="OTPAuxFile" src="How to use Keepass2Android with YubiKey NEO_OTPAuxFile_thumb.png" alt="OTPAuxFile" width="513" height="40" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p> <a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767825"><img title="OTPAuxFile" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767826" alt="OTPAuxFile" width="513" height="40" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p>Make sure you make <strong>both files</strong> available to Keepass2Android, e.g. by placing them both in your Dropbox.</p> <p>Make sure you make <strong>both files</strong> available to Keepass2Android, e.g. by placing them both in your Dropbox.</p>
<p>Now you should check your NDEF setup of the Yubikey NEO. Therefore, go to the Tools menu in the Yubico Personalization Utility. Select the same slot as used for OTPs with Keepass 2. The default setting for NDEF type and payload should work. If you experience <p>Now you should check your NDEF setup of the Yubikey NEO. Therefore, go to the Tools menu in the Yubico Personalization Utility. Select the same slot as used for OTPs with Keepass 2. The default setting for NDEF type and payload should work. If you experience
problems, you may use the configuration as shown in this screenshot or simply press the &ldquo;Reset&rdquo; button:</p> problems, you may use the configuration as shown in this screenshot or simply press the &ldquo;Reset&rdquo; button:</p>
<p><a href="How to use Keepass2Android with YubiKey NEO_image_2.png"><img title="image" src="How to use Keepass2Android with YubiKey NEO_image_thumb.png" alt="image" width="760" height="622" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p> <p><a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767911"><img title="image" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767912" alt="image" width="760" height="622" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p><br> <p><br>
<br> <br>
In Keepass2Android, select &quot;Open file&quot; and locate your database file, e.g. yubi.kdbx.<br> In Keepass2Android, select &quot;Open file&quot; and locate your database file, e.g. yubi.kdbx.<br>
<br> <br>
In the password screen under &quot;Select master key type&quot; select &quot;Password &#43; OTP&quot;.</p> In the password screen under &quot;Select master key type&quot; select &quot;Password &#43; OTP&quot;.</p>
<p><a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-50_2.png"><img title="Screenshot_2013-12-13-06-38-50" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-50_thumb.png" alt="Screenshot_2013-12-13-06-38-50" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p> <p><a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767913"><img title="Screenshot_2013-12-13-06-38-50" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767914" alt="Screenshot_2013-12-13-06-38-50" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p>Click &quot;Load auxiliary OTP file&quot;. This is required to load the information how many OTPs must be entered. As loading the file might require user action in some cases, this is not performed automatically.<br> <p>Click &quot;Load auxiliary OTP file&quot;. This is required to load the information how many OTPs must be entered. As loading the file might require user action in some cases, this is not performed automatically.<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-12_2.png"><img title="Screenshot_2013-12-13-06-38-12" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-12_thumb.png" alt="Screenshot_2013-12-13-06-38-12" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br> <a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767915"><img title="Screenshot_2013-12-13-06-38-12" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767916" alt="Screenshot_2013-12-13-06-38-12" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
After loading the OTP auxiliary file, you should see a few text fields for entering the OTPs. Now swipe your YubiKey NEO at the back of your Android device. If you have multiple apps which can handle NFC actions, you might be prompted to select which app to After loading the OTP auxiliary file, you should see a few text fields for entering the OTPs. Now swipe your YubiKey NEO at the back of your Android device. If you have multiple apps which can handle NFC actions, you might be prompted to select which app to
use. Select Keepass2Android in this case. Swipe your YubiKey again until all OTP fields are filled. Note: You don't need to select the next text field, this is done automatically!<br> use. Select Keepass2Android in this case. Swipe your YubiKey again until all OTP fields are filled. Note: You don't need to select the next text field, this is done automatically!<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-36_2.png"><img title="Screenshot_2013-12-13-06-38-36" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-36_thumb.png" alt="Screenshot_2013-12-13-06-38-36" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br> <a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767917"><img title="Screenshot_2013-12-13-06-38-36" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767918" alt="Screenshot_2013-12-13-06-38-36" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
Don't forget to also enter your password and click OK. You will see the &ldquo;Saving auxiliary OTP file&hellip;&rdquo; dialog. Note that there is some encryption envolved which is probably fast on your PC but might take some time on your mobile device. You Don't forget to also enter your password and click OK. You will see the &ldquo;Saving auxiliary OTP file&hellip;&rdquo; dialog. Note that there is some encryption envolved which is probably fast on your PC but might take some time on your mobile device. You
can reduce the look-ahead window length to speed this up.<br> can reduce the look-ahead window length to speed this up.<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-39-47_2.png"><img title="Screenshot_2013-12-13-06-39-47" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-39-47_thumb.png" alt="Screenshot_2013-12-13-06-39-47" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p> <a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767919"><img title="Screenshot_2013-12-13-06-39-47" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767920" alt="Screenshot_2013-12-13-06-39-47" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<h2>&nbsp;</h2> <h2>&nbsp;</h2>
<h2>A note about offline access</h2> <h2>A note about offline access</h2>
<p>If your database is stored in the cloud or on the web, you can still access it if you have enabled file caching (which is on by default). With OTPs, this becomes a little bit more complicated: If you repeatedly open your datbase while being offline, the <p>If your database is stored in the cloud or on the web, you can still access it if you have enabled file caching (which is on by default). With OTPs, this becomes a little bit more complicated: If you repeatedly open your datbase while being offline, the
OTP counter stored on the Yubikey will be increased. Don&rsquo;t forget to synchronize the database (which will also synchronize the OTP auxiliary file) as soon as possible to avoid problems with accessing your database on other devices! If you often need OTP counter stored on the Yubikey will be increased. Don&rsquo;t forget to synchronize the database (which will also synchronize the OTP auxiliary file) as soon as possible to avoid problems with accessing your database on other devices! If you often need
to open the database while you&rsquo;re offline, consider increasing the look-ahead window length!</p> to open the database while you&rsquo;re offline, consider increasing the look-ahead window length!</p>
</div><div class="ClearBoth"></div> </div><div class="ClearBoth"></div>

View File

@@ -2,7 +2,7 @@ Keepass2Android's apk is pretty big, e.g. when comparing to Keepassdroid. The ma
Here's a list of what is contained in the Keepass2Android 0.9.1 application package: Here's a list of what is contained in the Keepass2Android 0.9.1 application package:
``` {{
Mono for Android Mono for Android
.net dlls 5.0 MB .net dlls 5.0 MB
Runtime 2.5 MB Runtime 2.5 MB
@@ -22,4 +22,4 @@ Java/Mono bindings 0.5 MB
rest 0.3 MB rest 0.3 MB
TOTAL 13 MB TOTAL 13 MB
``` }}

View File

@@ -1,6 +1,3 @@
<h1 align="center"><img src="/src/keepass2android/Resources/mipmap-xxxhdpi/ic_launcher_online.png" align="center" width="100" alt="Keepass2Android Logo">Keepass2Android</h1>
# What is Keepass2Android? # What is Keepass2Android?
Keepass2Android is a password manager app. It allows to store and retrieve passwords and other sensitive information in a file called "database". This database is secured with a so-called master password. The master password typically is a strong password and can be complemented with a second factor for additional security. Keepass2Android is a password manager app. It allows to store and retrieve passwords and other sensitive information in a file called "database". This database is secured with a so-called master password. The master password typically is a strong password and can be complemented with a second factor for additional security.
The password database file can be synchronized across different devices. This works best using one of the built-in cloud storage options, but can also be performed with third-party apps. Keepass2Android is compatible with Keepass 1 and Keepass 2 on Windows and KeepassX on Linux. The password database file can be synchronized across different devices. This works best using one of the built-in cloud storage options, but can also be performed with third-party apps. Keepass2Android is compatible with Keepass 1 and Keepass 2 on Windows and KeepassX on Linux.
@@ -8,15 +5,14 @@ The password database file can be synchronized across different devices. This wo
# Where to get it? # Where to get it?
Regular stable releases of Keepass2Android are available on [Google Play](https://play.google.com/store/apps/details?id=keepass2android.keepass2android). Regular stable releases of Keepass2Android are available on [Google Play](https://play.google.com/store/apps/details?id=keepass2android.keepass2android).
Beta-releases can be obtained by opting in to the [Beta testing channel](https://play.google.com/apps/testing/keepass2android.keepass2android) or [Beta testing channel for Keepass2Android Offline](https://play.google.com/apps/testing/keepass2android.keepass2android_nonet). Beta-releases can be obtained by opting in to the [Beta testing channel](https://play.google.com/apps/testing/keepass2android.keepass2android) or [Beta testing channel for Keepass2Android Offline](https://play.google.com/apps/testing/keepass2android.keepass2android_nonet). Please join the [Beta tester group](https://plus.google.com/communities/107293657110547776032) for news and discussions about the latest beta releases.
# How can I contribute? # How can I contribute?
* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android) * Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android)
* Add features by [creating a plugin](How-to-create-a-plug-in_.md) or creating a pull request. You might want to contact me before you start working so I can coordinate efforts. * Add features by [creating a plugin](How-to-create-a-plug-in_.md) or creating a pull request. You might want to contact me before you start working so I can coordinate efforts.
* [Become a GitHub sponsor to boost 🚀 development](https://github.com/sponsors/PhilippC)
* [Make a donation](http://philipp.crocoll.net/donate.php) * [Make a donation](http://philipp.crocoll.net/donate.php)
# How do I learn more? # How do I learn more?
Please see the [documentation](Documentation.md). Please see the [documentation](Documentation.md).
[![Build Status](https://www.bitrise.io/app/43a23ab54dee9f7e/status.svg?token=2vryTsMQzTX3XRPikhgRwA&branch=master)](https://www.bitrise.io/app/43a23ab54dee9f7e) [![Build Status](https://www.bitrise.io/app/43a23ab54dee9f7e/status.svg?token=2vryTsMQzTX3XRPikhgRwA&branch=nonet)](https://www.bitrise.io/app/43a23ab54dee9f7e)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0B109C0E-0514-4340-8779-5BD6A0DDE84E}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AdalBindings</RootNamespace>
<AssemblyName>AdalBindings</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.1</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)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\adal-1.14.0.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gson-2.3.1.jar" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.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

@@ -1,48 +0,0 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

View File

@@ -1,24 +0,0 @@
This directory is for Android .jars.
There are 2 types of jars that are supported:
== Input Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
Set the build action for these jars in the properties page to "InputJar".
== Reference Jars ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".

View File

@@ -1,30 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// 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("AdalBindings")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AdalBindings")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// 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

@@ -1,14 +0,0 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

View File

@@ -1,13 +0,0 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

View File

@@ -1,13 +0,0 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
<remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='AuthenticationActivity']" />
<remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='DateTimeAdapter']" />
<remove-node path="/api/package[@name='com.microsoft.aad.adal']" />
</metadata>

View File

@@ -10,9 +10,8 @@
<RootNamespace>AndroidFileChooserBinding</RootNamespace> <RootNamespace>AndroidFileChooserBinding</RootNamespace>
<AssemblyName>AndroidFileChooserBinding</AssemblyName> <AssemblyName>AndroidFileChooserBinding</AssemblyName>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion> <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>

View File

@@ -26,7 +26,6 @@
android:hint="@string/http_auth_dialog_password" android:hint="@string/http_auth_dialog_password"
android:inputType="textPassword" android:inputType="textPassword"
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="20dp" android:paddingBottom="20dp" />
android:importantForAccessibility="no" />
</LinearLayout> </LinearLayout>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -10,10 +10,8 @@
<RootNamespace>JavaFileStorageBindings</RootNamespace> <RootNamespace>JavaFileStorageBindings</RootNamespace>
<AssemblyName>JavaFileStorageBindings</AssemblyName> <AssemblyName>JavaFileStorageBindings</AssemblyName>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion> <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -62,6 +60,7 @@
</LibraryProjectZip> </LibraryProjectZip>
<None Include="Jars\AboutJars.txt" /> <None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" /> <None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\adal-1.14.0.aar" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" /> <TransformFile Include="Transforms\Metadata.xml" />
@@ -83,7 +82,10 @@
</XamarinComponentReference> </XamarinComponentReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" /> <EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gson-2.3.1.jar" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedReferenceJar Include="Jars\msa-auth-0.8.6\classes-msa-auth.jar" /> <EmbeddedReferenceJar Include="Jars\msa-auth-0.8.6\classes-msa-auth.jar" />
@@ -140,18 +142,12 @@
<EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" /> <EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedJar Include="Jars\dropbox-core-sdk-3.1.1.jar" /> <EmbeddedJar Include="Jars\dropbox-core-sdk-3.0.3.jar" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedReferenceJar Include="Jars\gson-2.8.1.jar" /> <EmbeddedReferenceJar Include="Jars\okhttp-3.9.0.jar" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-digest-2.5.jar" /> <EmbeddedReferenceJar Include="Jars\okio-1.13.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okio-2.9.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-4.10.0-RC1.jar" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -11,8 +11,6 @@
<remove-node path="/api/package[@name='com.jcraft.jsch.jcraft']" /> <remove-node path="/api/package[@name='com.jcraft.jsch.jcraft']" />
<remove-node path="/api/package[@name='com.jcraft.jzlib']" /> <remove-node path="/api/package[@name='com.jcraft.jzlib']" />
<remove-node path="/api/package[@name='com.pcloud.sdk']" />
<remove-node path="/api/package[@name='com.dropbox.core']" /> <remove-node path="/api/package[@name='com.dropbox.core']" />
<remove-node path="/api/package[@name='com.dropbox.core.util']" /> <remove-node path="/api/package[@name='com.dropbox.core.util']" />
<remove-node path="/api/package[@name='com.dropbox.core.http']" /> <remove-node path="/api/package[@name='com.dropbox.core.http']" />

View File

@@ -10,9 +10,8 @@
<RootNamespace>KP2AKdbLibraryBinding</RootNamespace> <RootNamespace>KP2AKdbLibraryBinding</RootNamespace>
<AssemblyName>KP2AKdbLibraryBinding</AssemblyName> <AssemblyName>KP2AKdbLibraryBinding</AssemblyName>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion> <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -53,11 +52,10 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<LibraryProjectZip Include="..\java\KP2AKdbLibrary\app\build\outputs\aar\app-debug.aar">
<Link>Jars\app-debug.aar</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" /> <None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" /> <None Include="Additions\AboutAdditions.txt" />
<EmbeddedNativeLibrary Include="libs\armeabi-v7a\libfinal-key.so" />
<EmbeddedNativeLibrary Include="libs\armeabi\libfinal-key.so" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<TransformFile Include="Transforms\Metadata.xml"> <TransformFile Include="Transforms\Metadata.xml">
@@ -67,7 +65,9 @@
<TransformFile Include="Transforms\EnumMethods.xml" /> <TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="libs\" /> <EmbeddedJar Include="..\java\KP2AKdbLibrary\bin\kp2akdblibrary.jar">
<Link>Jars\kp2akdblibrary.jar</Link>
</EmbeddedJar>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

Binary file not shown.

View File

@@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio 15
VisualStudioVersion = 16.0.29418.71 VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject EndProject
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aBusinessLogic", "Kp2aBu
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}"
@@ -25,8 +23,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -109,8 +105,8 @@ Global
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = Debug|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = Debug|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -151,30 +147,6 @@ Global
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.Build.0 = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.Build.0 = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.Build.0 = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -187,8 +159,8 @@ Global
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -205,8 +177,8 @@ Global
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -223,8 +195,8 @@ Global
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -271,30 +243,6 @@ Global
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU {3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU {3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.Build.0 = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.ActiveCfg = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.Build.0 = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.Build.0 = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.ActiveCfg = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.Build.0 = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.ActiveCfg = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.Build.0 = Release|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -367,27 +367,5 @@ namespace KeePassLib.Cryptography
Debug.Assert(iPos == pbRes.Length); Debug.Assert(iPos == pbRes.Length);
return pbRes; return pbRes;
} }
private static int g_iWeakSeed = 0;
public static Random NewWeakRandom()
{
long s64 = DateTime.UtcNow.ToBinary();
int s32 = (int)((s64 >> 32) ^ s64);
lock (g_oSyncRoot)
{
unchecked
{
g_iWeakSeed += 0x78A8C4B7; // Prime number
s32 ^= g_iWeakSeed;
}
}
// Prevent overflow in the Random constructor of .NET 2.0
if (s32 == int.MinValue) s32 = int.MaxValue;
return new Random(s32);
}
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -20,67 +20,28 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text; using System.Text;
#if !KeePassUAP #if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif #endif
using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
public static class CryptoUtil public static class CryptoUtil
{ {
private static bool? g_obProtData = null;
public static bool IsProtectedDataSupported
{
get
{
if (g_obProtData.HasValue) return g_obProtData.Value;
bool b = false;
try
{
Random r = CryptoRandom.NewWeakRandom();
byte[] pbData = new byte[137];
r.NextBytes(pbData);
byte[] pbEnt = new byte[41];
r.NextBytes(pbEnt);
byte[] pbEnc = ProtectedData.Protect(pbData, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbEnc != null) && !MemUtil.ArraysEqual(pbEnc, pbData))
{
byte[] pbDec = ProtectedData.Unprotect(pbEnc, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbDec != null) && MemUtil.ArraysEqual(pbDec, pbData))
b = true;
}
}
catch (Exception) { Debug.Assert(false); }
Debug.Assert(b); // Should be supported on all systems
g_obProtData = b;
return b;
}
}
public static byte[] HashSha256(byte[] pbData) public static byte[] HashSha256(byte[] pbData)
{ {
if (pbData == null) throw new ArgumentNullException("pbData"); if(pbData == null) throw new ArgumentNullException("pbData");
return HashSha256(pbData, 0, pbData.Length); return HashSha256(pbData, 0, pbData.Length);
} }
public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount) public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount)
{ {
if (pbData == null) throw new ArgumentNullException("pbData"); if(pbData == null) throw new ArgumentNullException("pbData");
#if DEBUG #if DEBUG
byte[] pbCopy = new byte[pbData.Length]; byte[] pbCopy = new byte[pbData.Length];
@@ -88,7 +49,7 @@ namespace KeePassLib.Cryptography
#endif #endif
byte[] pbHash; byte[] pbHash;
using (SHA256Managed h = new SHA256Managed()) using(SHA256Managed h = new SHA256Managed())
{ {
pbHash = h.ComputeHash(pbData, iOffset, cbCount); pbHash = h.ComputeHash(pbData, iOffset, cbCount);
} }
@@ -105,22 +66,6 @@ namespace KeePassLib.Cryptography
return pbHash; return pbHash;
} }
internal static byte[] HashSha256(string strFilePath)
{
byte[] pbHash = null;
using (FileStream fs = new FileStream(strFilePath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
using (SHA256Managed h = new SHA256Managed())
{
pbHash = h.ComputeHash(fs);
}
}
return pbHash;
}
/// <summary> /// <summary>
/// Create a cryptographic key of length <paramref name="cbOut" /> /// Create a cryptographic key of length <paramref name="cbOut" />
/// (in bytes) from <paramref name="pbIn" />. /// (in bytes) from <paramref name="pbIn" />.
@@ -128,34 +73,34 @@ namespace KeePassLib.Cryptography
public static byte[] ResizeKey(byte[] pbIn, int iInOffset, public static byte[] ResizeKey(byte[] pbIn, int iInOffset,
int cbIn, int cbOut) int cbIn, int cbOut)
{ {
if (pbIn == null) throw new ArgumentNullException("pbIn"); if(pbIn == null) throw new ArgumentNullException("pbIn");
if (cbOut < 0) throw new ArgumentOutOfRangeException("cbOut"); if(cbOut < 0) throw new ArgumentOutOfRangeException("cbOut");
if (cbOut == 0) return MemUtil.EmptyByteArray; if(cbOut == 0) return MemUtil.EmptyByteArray;
byte[] pbHash; byte[] pbHash;
if (cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn); if(cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn);
else else
{ {
using (SHA512Managed h = new SHA512Managed()) using(SHA512Managed h = new SHA512Managed())
{ {
pbHash = h.ComputeHash(pbIn, iInOffset, cbIn); pbHash = h.ComputeHash(pbIn, iInOffset, cbIn);
} }
} }
if (cbOut == pbHash.Length) return pbHash; if(cbOut == pbHash.Length) return pbHash;
byte[] pbRet = new byte[cbOut]; byte[] pbRet = new byte[cbOut];
if (cbOut < pbHash.Length) if(cbOut < pbHash.Length)
Array.Copy(pbHash, pbRet, cbOut); Array.Copy(pbHash, pbRet, cbOut);
else else
{ {
int iPos = 0; int iPos = 0;
ulong r = 0; ulong r = 0;
while (iPos < cbOut) while(iPos < cbOut)
{ {
Debug.Assert(pbHash.Length == 64); Debug.Assert(pbHash.Length == 64);
using (HMACSHA256 h = new HMACSHA256(pbHash)) using(HMACSHA256 h = new HMACSHA256(pbHash))
{ {
byte[] pbR = MemUtil.UInt64ToBytes(r); byte[] pbR = MemUtil.UInt64ToBytes(r);
byte[] pbPart = h.ComputeHash(pbR); byte[] pbPart = h.ComputeHash(pbR);
@@ -180,75 +125,5 @@ namespace KeePassLib.Cryptography
MemUtil.ZeroByteArray(pbHash); MemUtil.ZeroByteArray(pbHash);
return pbRet; return pbRet;
} }
#if !KeePassUAP
private static bool? g_obAesCsp = null;
internal static SymmetricAlgorithm CreateAes()
{
if (g_obAesCsp.HasValue)
return (g_obAesCsp.Value ? CreateAesCsp() : new RijndaelManaged());
SymmetricAlgorithm a = CreateAesCsp();
g_obAesCsp = (a != null);
return (a ?? new RijndaelManaged());
}
private static SymmetricAlgorithm CreateAesCsp()
{
try
{
// On Windows, the CSP implementation is only minimally
// faster (and for key derivations it's not used anyway,
// as KeePass uses a native implementation based on
// CNG/BCrypt, which is much faster)
if (!NativeLib.IsUnix()) return null;
string strFqn = Assembly.CreateQualifiedName(
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Security.Cryptography.AesCryptoServiceProvider");
Type t = Type.GetType(strFqn);
if (t == null) return null;
return (Activator.CreateInstance(t) as SymmetricAlgorithm);
}
catch (Exception) { Debug.Assert(false); }
return null;
}
#endif
public static byte[] ProtectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, true, pbOptEntropy, s);
}
public static byte[] UnprotectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, false, pbOptEntropy, s);
}
private static byte[] ProtectDataPriv(byte[] pb, bool bProtect,
byte[] pbOptEntropy, DataProtectionScope s)
{
if (pb == null) throw new ArgumentNullException("pb");
if ((pbOptEntropy != null) && (pbOptEntropy.Length == 0))
pbOptEntropy = null;
if (CryptoUtil.IsProtectedDataSupported)
{
if (bProtect)
return ProtectedData.Protect(pb, pbOptEntropy, s);
return ProtectedData.Unprotect(pb, pbOptEntropy, s);
}
Debug.Assert(false);
byte[] pbCopy = new byte[pb.Length];
Array.Copy(pb, pbCopy, pb.Length);
return pbCopy;
}
} }
} }

View File

@@ -21,7 +21,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using keepass2android;
#if KeePassUAP #if KeePassUAP
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Engines;
@@ -144,7 +144,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
ulong uNumRounds) ulong uNumRounds)
{ {
Kp2aLog.Log("Warning: transforming key managed. Expect this to be slow!");
#if KeePassUAP #if KeePassUAP
KeyParameter kp = new KeyParameter(pbKeySeed32); KeyParameter kp = new KeyParameter(pbKeySeed32);
AesEngine aes = new AesEngine(); AesEngine aes = new AesEngine();

View File

@@ -46,8 +46,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
private const ulong NbBlockSizeInQW = NbBlockSize / 8UL; private const ulong NbBlockSizeInQW = NbBlockSize / 8UL;
private const ulong NbSyncPoints = 4; private const ulong NbSyncPoints = 4;
private const ulong NbAddressesInBlock = 128;
private const int NbPreHashDigestLength = 64; private const int NbPreHashDigestLength = 64;
private const int NbPreHashSeedLength = NbPreHashDigestLength + 8; private const int NbPreHashSeedLength = NbPreHashDigestLength + 8;
@@ -58,7 +56,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
private sealed class Argon2Ctx private sealed class Argon2Ctx
{ {
public Argon2Type Type = Argon2Type.D;
public uint Version = 0; public uint Version = 0;
public ulong Lanes = 0; public ulong Lanes = 0;
@@ -92,9 +89,9 @@ namespace KeePassLib.Cryptography.KeyDerivation
} }
} }
private byte[] Argon2Transform(byte[] pbMsg, byte[] pbSalt, uint uParallel, private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel,
ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey, ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey,
byte[] pbAssocData) byte[] pbAssocData)
{ {
pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray); pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray);
pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray); pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray);
@@ -104,7 +101,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
#endif #endif
Argon2Ctx ctx = new Argon2Ctx(); Argon2Ctx ctx = new Argon2Ctx();
ctx.Type = m_t;
ctx.Version = uVersion; ctx.Version = uVersion;
ctx.Lanes = uParallel; ctx.Lanes = uParallel;
@@ -141,7 +137,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0); MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx((uint)m_t, pbBuf, 0); MemUtil.UInt32ToBytesEx(0, pbBuf, 0); // Argon2d type = 0
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0); MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
@@ -491,43 +487,18 @@ namespace KeePassLib.Cryptography.KeyDerivation
private static void FillSegmentThr(object o) private static void FillSegmentThr(object o)
{ {
Argon2ThreadInfo ti = (o as Argon2ThreadInfo); Argon2ThreadInfo ti = (o as Argon2ThreadInfo);
if (ti == null) { Debug.Assert(false); return; } if(ti == null) { Debug.Assert(false); return; }
try try
{ {
Argon2Ctx ctx = ti.Context; Argon2Ctx ctx = ti.Context;
if (ctx == null) { Debug.Assert(false); return; } if(ctx == null) { Debug.Assert(false); return; }
Debug.Assert(ctx.Version >= MinVersion); Debug.Assert(ctx.Version >= MinVersion);
bool bCanXor = (ctx.Version >= 0x13U); bool bCanXor = (ctx.Version >= 0x13U);
ulong[] pbR = new ulong[NbBlockSizeInQW];
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
ulong[] pbAddrInputZero = null;
bool bDataIndependentAddr = ((ctx.Type == Argon2Type.ID) &&
(ti.Pass == 0) && (ti.Slice < (NbSyncPoints / 2)));
if (bDataIndependentAddr)
{
pbAddrInputZero = new ulong[NbBlockSizeInQW * 3];
const int iInput = (int)NbBlockSizeInQW;
pbAddrInputZero[iInput] = ti.Pass;
pbAddrInputZero[iInput + 1] = ti.Lane;
pbAddrInputZero[iInput + 2] = ti.Slice;
pbAddrInputZero[iInput + 3] = ctx.MemoryBlocks;
pbAddrInputZero[iInput + 4] = ctx.TCost;
pbAddrInputZero[iInput + 5] = (ulong)ctx.Type;
}
ulong uStart = 0; ulong uStart = 0;
if ((ti.Pass == 0) && (ti.Slice == 0)) if((ti.Pass == 0) && (ti.Slice == 0)) uStart = 2;
{
uStart = 2;
if (bDataIndependentAddr)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
}
ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice * ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice *
ctx.SegmentLength) + uStart; ctx.SegmentLength) + uStart;
@@ -535,23 +506,17 @@ namespace KeePassLib.Cryptography.KeyDerivation
ulong uPrev = (((uCur % ctx.LaneLength) == 0) ? ulong uPrev = (((uCur % ctx.LaneLength) == 0) ?
(uCur + ctx.LaneLength - 1UL) : (uCur - 1UL)); (uCur + ctx.LaneLength - 1UL) : (uCur - 1UL));
for (ulong i = uStart; i < ctx.SegmentLength; ++i) ulong[] pbR = new ulong[NbBlockSizeInQW];
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
for(ulong i = uStart; i < ctx.SegmentLength; ++i)
{ {
if ((uCur % ctx.LaneLength) == 1) if((uCur % ctx.LaneLength) == 1)
uPrev = uCur - 1UL; uPrev = uCur - 1UL;
ulong uPseudoRand; ulong uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW];
if (bDataIndependentAddr)
{
ulong iMod = i % NbAddressesInBlock;
if (iMod == 0)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
uPseudoRand = pbAddrInputZero[iMod];
}
else uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW];
ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes; ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes;
if ((ti.Pass == 0) && (ti.Slice == 0)) if((ti.Pass == 0) && (ti.Slice == 0))
uRefLane = ti.Lane; uRefLane = ti.Lane;
ti.Index = i; ti.Index = i;
@@ -571,12 +536,11 @@ namespace KeePassLib.Cryptography.KeyDerivation
MemUtil.ZeroArray<ulong>(pbR); MemUtil.ZeroArray<ulong>(pbR);
MemUtil.ZeroArray<ulong>(pbTmp); MemUtil.ZeroArray<ulong>(pbTmp);
if (pbAddrInputZero != null) MemUtil.ZeroArray<ulong>(pbAddrInputZero);
} }
catch (Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
try { ti.Finished.Set(); } try { ti.Finished.Set(); }
catch (Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
} }
#if ARGON2_B2ROUND_ARRAYS #if ARGON2_B2ROUND_ARRAYS
@@ -646,19 +610,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
XorBlock(pMem, uNext, pbR, 0); XorBlock(pMem, uNext, pbR, 0);
} }
private static void NextAddresses(ulong[] pbAddrInputZero, ulong[] pbR,
ulong[] pbTmp)
{
// pbAddrInputZero contains an address block, an input block and a zero block
const ulong uAddr = 0;
const ulong uInput = NbBlockSizeInQW;
const ulong uZero = NbBlockSizeInQW * 2;
++pbAddrInputZero[uInput + 6];
FillBlock(pbAddrInputZero, uZero, uInput, uAddr, false, pbR, pbTmp);
FillBlock(pbAddrInputZero, uZero, uAddr, uAddr, false, pbR, pbTmp);
}
private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h) private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h)
{ {
ulong[] pqBlockHash = new ulong[NbBlockSizeInQW]; ulong[] pqBlockHash = new ulong[NbBlockSizeInQW];

View File

@@ -20,27 +20,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace KeePassLib.Cryptography.KeyDerivation namespace KeePassLib.Cryptography.KeyDerivation
{ {
public enum Argon2Type public sealed partial class Argon2Kdf : KdfEngine
{
// The values must be the same as in the Argon2 specification
D = 0,
ID = 2
}
public sealed partial class Argon2Kdf : KdfEngine
{ {
private static readonly PwUuid g_uuid = new PwUuid(new byte[] {
0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B,
private static readonly PwUuid g_uuidD = new PwUuid(new byte[] { 0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C });
0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B,
0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C });
private static readonly PwUuid g_uuidID = new PwUuid(new byte[] {
0x9E, 0x29, 0x8B, 0x19, 0x56, 0xDB, 0x47, 0x73,
0xB2, 0x3D, 0xFC, 0x3E, 0xC6, 0xF0, 0xA1, 0xE6 });
public const string ParamSalt = "S"; // Byte[] public const string ParamSalt = "S"; // Byte[]
public const string ParamParallelism = "P"; // UInt32 public const string ParamParallelism = "P"; // UInt32
@@ -66,37 +54,28 @@ namespace KeePassLib.Cryptography.KeyDerivation
internal const uint MinParallelism = 1; internal const uint MinParallelism = 1;
internal const uint MaxParallelism = (1 << 24) - 1; internal const uint MaxParallelism = (1 << 24) - 1;
internal const ulong DefaultIterations = 2; internal const ulong DefaultIterations = 2;
internal const ulong DefaultMemory = 64 * 1024 * 1024; // 64 MB internal const ulong DefaultMemory = 1024 * 1024; // 1 MB
internal const uint DefaultParallelism = 2; internal const uint DefaultParallelism = 2;
private readonly Argon2Type m_t; public override PwUuid Uuid
{
get { return g_uuid; }
}
public override PwUuid Uuid public override string Name
{ {
get { return ((m_t == Argon2Type.D) ? g_uuidD : g_uuidID); } get { return "Argon2"; }
} }
public override string Name
{
get { return ((m_t == Argon2Type.D) ? "Argon2d" : "Argon2id"); }
}
public Argon2Kdf() : this(Argon2Type.D)
{
}
public Argon2Kdf(Argon2Type t)
{
if ((t != Argon2Type.D) && (t != Argon2Type.ID))
throw new NotSupportedException();
m_t = t;
}
public override byte[] GetSeed(KdfParameters p) public override byte[] GetSeed(KdfParameters p)
{ return p.GetByteArray(ParamSalt); } { return p.GetByteArray(ParamSalt); }
public override KdfParameters GetDefaultParameters() public Argon2Kdf()
{
}
public override KdfParameters GetDefaultParameters()
{ {
KdfParameters p = base.GetDefaultParameters(); KdfParameters p = base.GetDefaultParameters();
@@ -112,7 +91,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
public override void Randomize(KdfParameters p) public override void Randomize(KdfParameters p)
{ {
if(p == null) { Debug.Assert(false); return; } if(p == null) { Debug.Assert(false); return; }
Debug.Assert(p.KdfUuid.Equals(this.Uuid)); Debug.Assert(g_uuid.Equals(p.KdfUuid));
byte[] pb = CryptoRandom.Instance.GetRandomBytes(32); byte[] pb = CryptoRandom.Instance.GetRandomBytes(32);
p.SetByteArray(ParamSalt, pb); p.SetByteArray(ParamSalt, pb);
@@ -148,59 +127,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
byte[] pbSecretKey = p.GetByteArray(ParamSecretKey); byte[] pbSecretKey = p.GetByteArray(ParamSecretKey);
byte[] pbAssocData = p.GetByteArray(ParamAssocData); byte[] pbAssocData = p.GetByteArray(ParamAssocData);
byte[] pbRet; byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt,
32, v, pbSecretKey, pbAssocData);
if (m_t == Argon2Type.ID) if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect();
{
pbRet = Argon2Transform(pbMsg, pbSalt, uPar, uMem,
uIt, 32, v, pbSecretKey, pbAssocData);
}
else
{
if (pbSecretKey != null)
{
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbSecretKey");
}
if (pbAssocData != null)
{
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbAssocData");
}
/*
byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt,
32, v, pbSecretKey, pbAssocData);
*/
IntPtr msgPtr = Marshal.AllocHGlobal(pbMsg.Length);
IntPtr saltPtr = Marshal.AllocHGlobal(pbSalt.Length);
IntPtr retPtr = Marshal.AllocHGlobal(32);
Marshal.Copy(pbMsg, 0, msgPtr, pbMsg.Length);
Marshal.Copy(pbSalt, 0, saltPtr, pbSalt.Length);
const UInt32 Argon2_d = 0;
int ret = argon2_hash(
(UInt32)uIt, (UInt32)(uMem / 1024), uPar,
msgPtr, (IntPtr)pbMsg.Length,
saltPtr, (IntPtr)pbSalt.Length,
retPtr, (IntPtr)32,
(IntPtr)0, (IntPtr)0, Argon2_d, v);
if (ret != 0)
{
throw new Exception("argon2_hash failed with " + ret);
}
pbRet = new byte[32];
Marshal.Copy(retPtr, pbRet, 0, 32);
Marshal.FreeHGlobal(msgPtr);
Marshal.FreeHGlobal(saltPtr);
Marshal.FreeHGlobal(retPtr);
}
if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect();
return pbRet; return pbRet;
} }
@@ -213,14 +143,5 @@ namespace KeePassLib.Cryptography.KeyDerivation
MaxIterations, uMilliseconds, true); MaxIterations, uMilliseconds, true);
return p; return p;
} }
[DllImport("argon2")]
static extern int argon2_hash(
UInt32 t_cost, UInt32 m_cost, UInt32 parallelism,
IntPtr pwd, IntPtr pwdlen,
IntPtr salt, IntPtr saltlen,
IntPtr hash, IntPtr hashlen,
IntPtr encoded, IntPtr encodedlen,
UInt32 type, UInt32 version);
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -41,11 +41,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
private static void EnsureInitialized() private static void EnsureInitialized()
{ {
if(g_l.Count != 0) return; if(g_l.Count > 0) return;
g_l.Add(new AesKdf()); g_l.Add(new AesKdf());
g_l.Add(new Argon2Kdf(Argon2Type.D)); g_l.Add(new Argon2Kdf());
g_l.Add(new Argon2Kdf(Argon2Type.ID));
} }
internal static KdfParameters GetDefaultParameters() internal static KdfParameters GetDefaultParameters()

View File

@@ -12,8 +12,8 @@
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile> <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass> <AndroidResgenClass>Resource</AndroidResgenClass>
<AssemblyName>KeePassLib2Android</AssemblyName> <AssemblyName>KeePassLib2Android</AssemblyName>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion> <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<NuGetPackageImportStamp>8482b288</NuGetPackageImportStamp> <NuGetPackageImportStamp>8482b288</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@@ -50,7 +50,6 @@
<HintPath>..\ProtoBuf\protobuf-net.dll</HintPath> <HintPath>..\ProtoBuf\protobuf-net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Security" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />
@@ -72,7 +71,6 @@
<Compile Include="Cryptography\KeyDerivation\KdfParameters.cs" /> <Compile Include="Cryptography\KeyDerivation\KdfParameters.cs" />
<Compile Include="Cryptography\KeyDerivation\KdfPool.cs" /> <Compile Include="Cryptography\KeyDerivation\KdfPool.cs" />
<Compile Include="IDatabaseFormat.cs" /> <Compile Include="IDatabaseFormat.cs" />
<Compile Include="Keys\KcpKeyFile.Xml.cs" />
<Compile Include="Kp2aLog.cs" /> <Compile Include="Kp2aLog.cs" />
<Compile Include="Resources\Resource.designer.cs" /> <Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Resources\KLRes.Generated.cs" /> <Compile Include="Resources\KLRes.Generated.cs" />
@@ -162,7 +160,6 @@
<Compile Include="Utility\UrlUtil.cs" /> <Compile Include="Utility\UrlUtil.cs" />
<Compile Include="Utility\TimeUtil.cs" /> <Compile Include="Utility\TimeUtil.cs" />
<Compile Include="Delegates\Handlers.cs" /> <Compile Include="Delegates\Handlers.cs" />
<Compile Include="Utility\XmlUtilEx.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />

View File

@@ -38,11 +38,9 @@ namespace KeePassLib.Keys
get; get;
} }
// /// <summary> // /// <summary>
// /// Clear the key and securely erase all security-critical information. // /// Clear the key and securely erase all security-critical information.
// /// </summary> // /// </summary>
// void Clear(); // void Clear();
uint GetMinKdbxVersion();
} }
} }

View File

@@ -45,12 +45,7 @@ namespace KeePassLib.Keys
get { return m_pbKey; } get { return m_pbKey; }
} }
public uint GetMinKdbxVersion() public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash)
{
return 0;
}
public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash)
{ {
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");

View File

@@ -1,281 +0,0 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using KeePassLib.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
[XmlType("KeyFile")]
public sealed class KfxFile
{
private const ulong KfxVersionCriticalMask = 0xFFFF000000000000UL;
private const int KfxDataHashLength = 4;
private KfxMeta m_meta = new KfxMeta();
public KfxMeta Meta
{
get { return m_meta; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_meta = value;
}
}
private KfxKey m_key = new KfxKey();
public KfxKey Key
{
get { return m_key; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_key = value;
}
}
public static KfxFile Create(ulong uVersion, byte[] pbKey, byte[] pbHash)
{
if(pbKey == null) throw new ArgumentNullException("pbKey");
if(pbKey.Length == 0) throw new ArgumentOutOfRangeException("pbKey");
if(uVersion == 0) uVersion = 0x0002000000000000;
// Null hash: generate one, empty hash: store no hash
if(pbHash == null) pbHash = HashData(pbKey);
VerifyHash(pbKey, pbHash);
KfxFile kf = new KfxFile();
if(uVersion == 0x0001000000000000)
kf.Meta.Version = "1.00"; // KeePass <= 2.46 used two zeros
else kf.Meta.Version = StrUtil.VersionToString(uVersion, 2);
if(uVersion == 0x0001000000000000)
kf.Key.Data.Value = Convert.ToBase64String(pbKey);
else if(uVersion == 0x0002000000000000)
{
kf.Key.Data.Value = FormatKeyHex(pbKey, 3);
if(pbHash.Length != 0)
kf.Key.Data.Hash = MemUtil.ByteArrayToHexString(pbHash);
}
else throw new NotSupportedException(KLRes.FileVersionUnsupported);
return kf;
}
internal static KfxFile Create(ulong uVersion, string strKey, string strHash)
{
byte[] pbKey = ParseKey(uVersion, strKey);
byte[] pbHash = ((strHash != null) ? ParseHash(strHash) : null);
return Create(uVersion, pbKey, pbHash);
}
internal static bool CanLoad(string strFilePath)
{
if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return false; }
try
{
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
using(Stream s = IOConnection.OpenRead(ioc))
{
return (Load(s) != null);
}
}
catch(Exception) { }
return false;
}
public static KfxFile Load(Stream s)
{
return XmlUtilEx.Deserialize<KfxFile>(s);
}
public void Save(Stream s)
{
XmlUtilEx.Serialize<KfxFile>(s, this, true);
}
private static string FormatKeyHex(byte[] pb, int cTabs)
{
StringBuilder sb = new StringBuilder();
string str = MemUtil.ByteArrayToHexString(pb);
for(int i = 0; i < str.Length; ++i)
{
if((i & 0x1F) == 0)
{
sb.AppendLine();
sb.Append('\t', cTabs);
}
else if((i & 0x07) == 0) sb.Append(' ');
sb.Append(str[i]);
}
sb.AppendLine();
if(cTabs > 0) sb.Append('\t', cTabs - 1);
return sb.ToString();
}
private ulong GetVersion()
{
string str = m_meta.Version;
if(string.IsNullOrEmpty(str)) return 0;
return StrUtil.ParseVersion(str);
}
public byte[] GetKey()
{
ulong uVersion = GetVersion();
byte[] pbKey = ParseKey(uVersion, m_key.Data.Value);
if((pbKey == null) || (pbKey.Length == 0))
throw new FormatException(KLRes.FileCorrupted);
byte[] pbHash = ParseHash(m_key.Data.Hash);
VerifyHash(pbKey, pbHash);
return pbKey;
}
private static byte[] HashData(byte[] pb)
{
return MemUtil.Mid(CryptoUtil.HashSha256(pb), 0, KfxDataHashLength);
}
private static void VerifyHash(byte[] pbKey, byte[] pbHash)
{
// The hash is optional; empty hash means success
if((pbHash == null) || (pbHash.Length == 0)) return;
byte[] pbHashCmp = HashData(pbKey);
if(!MemUtil.ArraysEqual(pbHash, pbHashCmp))
throw new Exception("Keyfile hash mismatch!");
}
private static byte[] ParseKey(ulong uVersion, string strKey)
{
if(strKey == null) throw new ArgumentNullException("strKey");
strKey = StrUtil.RemoveWhiteSpace(strKey);
if(string.IsNullOrEmpty(strKey)) return MemUtil.EmptyByteArray;
uVersion &= KfxVersionCriticalMask;
byte[] pbKey;
if(uVersion == 0x0001000000000000)
pbKey = Convert.FromBase64String(strKey);
else if(uVersion == 0x0002000000000000)
pbKey = ParseHex(strKey);
else throw new NotSupportedException(KLRes.FileVersionUnsupported);
return pbKey;
}
private static byte[] ParseHash(string strHash)
{
return ParseHex(strHash);
}
private static byte[] ParseHex(string str)
{
if(str == null) throw new ArgumentNullException("str");
if(str.Length == 0) return MemUtil.EmptyByteArray;
if(((str.Length & 1) != 0) || !StrUtil.IsHexString(str, true))
throw new FormatException();
return MemUtil.HexStringToByteArray(str);
}
}
public sealed class KfxMeta
{
private string m_strVersion = string.Empty;
[DefaultValue("")]
public string Version
{
get { return m_strVersion; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strVersion = value;
}
}
}
public sealed class KfxKey
{
private KfxData m_data = new KfxData();
public KfxData Data
{
get { return m_data; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_data = value;
}
}
}
public sealed class KfxData
{
private string m_strHash = string.Empty;
[DefaultValue("")]
[XmlAttribute("Hash")]
public string Hash
{
get { return m_strHash; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strHash = value;
}
}
private string m_strValue = string.Empty;
[DefaultValue("")]
[XmlText]
public string Value
{
get { return m_strValue; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strValue = value;
}
}
}
}

View File

@@ -64,12 +64,7 @@ namespace KeePassLib.Keys
get { return m_pbKeyData; } get { return m_pbKeyData; }
} }
public uint GetMinKdbxVersion() public IOConnectionInfo Ioc
{
return 0;
}
public IOConnectionInfo Ioc
{ {
get { return m_ioc; } get { return m_ioc; }
} }
@@ -127,9 +122,10 @@ namespace KeePassLib.Keys
#endif #endif
} }
byte[] pbKey = LoadKeyFile(pbFileData); byte[] pbKey = LoadXmlKeyFile(pbFileData);
if(pbKey == null) pbKey = LoadKeyFile(pbFileData);
if (pbKey == null) throw new InvalidOperationException(); if(pbKey == null) throw new InvalidOperationException();
m_ioc = iocKeyFile; m_ioc = iocKeyFile;
m_pbKeyData = new ProtectedBinary(true, pbKey); m_pbKeyData = new ProtectedBinary(true, pbKey);
@@ -149,60 +145,54 @@ namespace KeePassLib.Keys
// } // }
private static byte[] LoadKeyFile(byte[] pbFileData) private static byte[] LoadKeyFile(byte[] pbFileData)
{ {
if (pbFileData == null) throw new ArgumentNullException("pbFileData"); if(pbFileData == null) { Debug.Assert(false); return null; }
byte[] pbKey = LoadKeyFileXml(pbFileData); int iLength = pbFileData.Length;
if (pbKey != null) return pbKey;
int cb = pbFileData.Length; byte[] pbKey = null;
if (cb == 32) return pbFileData; if(iLength == 32) pbKey = LoadBinaryKey32(pbFileData);
else if(iLength == 64) pbKey = LoadHexKey32(pbFileData);
if (cb == 64) if(pbKey == null)
{ pbKey = CryptoUtil.HashSha256(pbFileData);
pbKey = LoadKeyFileHex(pbFileData);
if (pbKey != null) return pbKey;
}
return CryptoUtil.HashSha256(pbFileData); return pbKey;
} }
private static byte[] LoadKeyFileXml(byte[] pbFileData) private static byte[] LoadBinaryKey32(byte[] pbFileData)
{ {
KfxFile kf; if(pbFileData == null) { Debug.Assert(false); return null; }
try if(pbFileData.Length != 32) { Debug.Assert(false); return null; }
{
using (MemoryStream ms = new MemoryStream(pbFileData, false))
{
kf = KfxFile.Load(ms);
}
}
catch (Exception) { return null; }
// We have a syntactically valid XML key file; return pbFileData;
// failing to verify the key should throw an exception }
return ((kf != null) ? kf.GetKey() : null);
}
private static byte[] LoadKeyFileHex(byte[] pbFileData) private static byte[] LoadHexKey32(byte[] pbFileData)
{ {
if (pbFileData == null) { Debug.Assert(false); return null; } if(pbFileData == null) { Debug.Assert(false); return null; }
if(pbFileData.Length != 64) { Debug.Assert(false); return null; }
try try
{ {
int cc = pbFileData.Length; if(!StrUtil.IsHexString(pbFileData, true)) return null;
if ((cc & 1) != 0) { Debug.Assert(false); return null; }
if (!StrUtil.IsHexString(pbFileData, true)) return null; string strHex = StrUtil.Utf8.GetString(pbFileData);
byte[] pbKey = MemUtil.HexStringToByteArray(strHex);
if((pbKey == null) || (pbKey.Length != 32))
{
Debug.Assert(false);
return null;
}
string strHex = StrUtil.Utf8.GetString(pbFileData); return pbKey;
return MemUtil.HexStringToByteArray(strHex); }
} catch(Exception) { Debug.Assert(false); }
catch (Exception) { Debug.Assert(false); }
return null;
}
return null;
}
/// <summary> /// <summary>
/// Create a new, random key-file. /// Create a new, random key-file.
/// </summary> /// </summary>

View File

@@ -53,12 +53,7 @@ namespace KeePassLib.Keys
get { return m_pbKeyData; } get { return m_pbKeyData; }
} }
public uint GetMinKdbxVersion() public KcpPassword(byte[] pbPasswordUtf8)
{
return 0;
}
public KcpPassword(byte[] pbPasswordUtf8)
{ {
SetKey(pbPasswordUtf8); SetKey(pbPasswordUtf8);
} }

View File

@@ -21,6 +21,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Security; using System.Security;
#if !KeePassUAP #if !KeePassUAP
@@ -59,12 +60,7 @@ namespace KeePassLib.Keys
get { return m_pbKeyData; } get { return m_pbKeyData; }
} }
public uint GetMinKdbxVersion() /// <summary>
{
return 0;
}
/// <summary>
/// Construct a user account key. /// Construct a user account key.
/// </summary> /// </summary>
public KcpUserAccount() public KcpUserAccount()
@@ -77,7 +73,26 @@ namespace KeePassLib.Keys
// m_pbKeyData = null; // m_pbKeyData = null;
// } // }
private static byte[] LoadUserKey(bool bShowWarning) private static string GetUserKeyFilePath(bool bCreate)
{
#if KeePassRT
string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path;
#else
string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
#endif
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
strUserDir += PwDefs.ShortProductName;
if (bCreate && !Directory.Exists(strUserDir))
Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
return strUserDir + UserKeyFileName;
}
private static byte[] LoadUserKey(bool bShowWarning)
{ {
byte[] pbKey = null; byte[] pbKey = null;

View File

@@ -85,8 +85,8 @@ namespace keepass2android
{ {
if (!File.Exists(LogFilename)) if (!File.Exists(LogFilename))
{ {
File.Create(LogFilename).Dispose(); File.Create(LogFilename);
_logToFile = true; _logToFile = true;
} }
@@ -100,7 +100,8 @@ namespace keepass2android
int count = 0; int count = 0;
while (File.Exists(LogFilename + "." + count)) while (File.Exists(LogFilename + "." + count))
count++; count++;
File.Move(LogFilename, LogFilename + "." + count); if (count > 0)
File.Move(LogFilename, LogFilename + "." + count);
} }
@@ -118,10 +119,5 @@ namespace keepass2android
sendIntent.SetType("text/plain"); sendIntent.SetType("text/plain");
ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to...")); ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
} }
}
public static void LogTask(object task, string activityName)
{
Log($"Task in activity {activityName} changed to {task?.GetType()?.Name ?? "null"}");
}
}
} }

View File

@@ -302,7 +302,7 @@ namespace KeePassLib.Native
} }
catch (Exception e) catch (Exception e)
{ {
Kp2aLog.Log(e.ToString()); Kp2aLog.Log(e.Message);
return false; return false;
} }

View File

@@ -485,6 +485,12 @@ namespace KeePassLib
set { m_pbHashOfLastIO = value; } set { m_pbHashOfLastIO = value; }
} }
public bool UseFileTransactions
{
get { return m_bUseFileTransactions; }
set { m_bUseFileTransactions = value; }
}
public bool UseFileLocks public bool UseFileLocks
{ {
get { return m_bUseFileLocks; } get { return m_bUseFileLocks; }
@@ -587,7 +593,7 @@ namespace KeePassLib
/// </summary> /// </summary>
/// <param name="ioConnection">IO connection of the new database.</param> /// <param name="ioConnection">IO connection of the new database.</param>
/// <param name="pwKey">Key to open the database.</param> /// <param name="pwKey">Key to open the database.</param>
public void New(IOConnectionInfo ioConnection, CompositeKey pwKey, string filenameWithoutPathAndExt) public void New(IOConnectionInfo ioConnection, CompositeKey pwKey)
{ {
Debug.Assert(ioConnection != null); Debug.Assert(ioConnection != null);
if(ioConnection == null) throw new ArgumentNullException("ioConnection"); if(ioConnection == null) throw new ArgumentNullException("ioConnection");
@@ -602,11 +608,26 @@ namespace KeePassLib
m_bDatabaseOpened = true; m_bDatabaseOpened = true;
m_bModified = true; m_bModified = true;
m_pgRootGroup = new PwGroup(true, true, filenameWithoutPathAndExt, m_pgRootGroup = new PwGroup(true, true,
UrlUtil.StripExtension(UrlUtil.GetFileName(ioConnection.Path)),
PwIcon.FolderOpen); PwIcon.FolderOpen);
m_pgRootGroup.IsExpanded = true; m_pgRootGroup.IsExpanded = true;
} }
/// <summary>
/// Open a database. The URL may point to any supported data source.
/// </summary>
/// <param name="ioSource">IO connection to load the database from.</param>
/// <param name="pwKey">Key used to open the specified database.</param>
/// <param name="slLogger">Logger, which gets all status messages.</param>
public void Open(IOConnectionInfo ioSource, CompositeKey pwKey,
IStatusLogger slLogger, IDatabaseFormat format)
{
Open(IOConnection.OpenRead(ioSource), UrlUtil.StripExtension(
UrlUtil.GetFileName(ioSource.Path)), ioSource, pwKey, slLogger, format);
}
/// <summary> /// <summary>
/// Open a database. The URL may point to any supported data source. /// Open a database. The URL may point to any supported data source.
@@ -654,7 +675,37 @@ namespace KeePassLib
throw; throw;
} }
} }
/// <summary>
/// Save the currently opened database. The file is written to the location
/// it has been opened from.
/// </summary>
/// <param name="slLogger">Logger that recieves status information.</param>
public void Save(IStatusLogger slLogger)
{
Debug.Assert(!HasDuplicateUuids());
FileLock fl = null;
if(m_bUseFileLocks) fl = new FileLock(m_ioSource);
try
{
FileTransactionEx ft = new FileTransactionEx(m_ioSource,
m_bUseFileTransactions);
Stream s = ft.OpenWrite();
KdbxFile kdb = new KdbxFile(this);
kdb.Save(s, null, KdbpFile.GetFormatToUse(m_ioSource), slLogger);
ft.CommitWrite();
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
Debug.Assert(m_pbHashOfFileOnDisk != null);
}
finally { if(fl != null) fl.Dispose(); }
m_bModified = false;
}
/// <summary> /// <summary>
/// Save the currently opened database. The file is written to the given stream which is expected to be the original location. /// Save the currently opened database. The file is written to the given stream which is expected to be the original location.
@@ -672,6 +723,46 @@ namespace KeePassLib
m_bModified = false; m_bModified = false;
} }
/// <summary>
/// Save the currently opened database to a different location. If
/// <paramref name="bIsPrimaryNow" /> is <c>true</c>, the specified
/// location is made the default location for future saves
/// using <c>SaveDatabase</c>.
/// </summary>
/// <param name="ioConnection">New location to serialize the database to.</param>
/// <param name="bIsPrimaryNow">If <c>true</c>, the new location is made the
/// standard location for the database. If <c>false</c>, a copy of the currently
/// opened database is saved to the specified location, but it isn't
/// made the default location (i.e. no lock files will be moved for
/// example).</param>
/// <param name="slLogger">Logger that recieves status information.</param>
public void SaveAs(IOConnectionInfo ioConnection, bool bIsPrimaryNow,
IStatusLogger slLogger)
{
Debug.Assert(ioConnection != null);
if(ioConnection == null) throw new ArgumentNullException("ioConnection");
IOConnectionInfo ioCurrent = m_ioSource; // Remember current
m_ioSource = ioConnection;
byte[] pbHashCopy = m_pbHashOfFileOnDisk;
try { this.Save(slLogger); }
catch(Exception)
{
m_ioSource = ioCurrent; // Restore
m_pbHashOfFileOnDisk = pbHashCopy;
m_pbHashOfLastIO = null;
throw;
}
if(!bIsPrimaryNow)
{
m_ioSource = ioCurrent; // Restore
m_pbHashOfFileOnDisk = pbHashCopy;
}
}
/// <summary> /// <summary>
/// Closes the currently opened database. No confirmation message is shown /// Closes the currently opened database. No confirmation message is shown

View File

@@ -360,12 +360,5 @@ namespace KeePassLib.Serialization
m_ioCredProtMode = IOCredProtMode.None; m_ioCredProtMode = IOCredProtMode.None;
} }
} }
public bool IsSameFileAs(IOConnectionInfo other)
{
if (other == null)
return false;
return Path == other.Path && UserName == other.UserName;
}
} }
} }

View File

@@ -23,7 +23,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using keepass2android;
#if !KeePassUAP #if !KeePassUAP
using System.Drawing; using System.Drawing;
#endif #endif
@@ -872,17 +872,8 @@ namespace KeePassLib.Serialization
pb = pb8; pb = pb8;
} }
long lSec = MemUtil.BytesToInt64(pb); long lSec = MemUtil.BytesToInt64(pb);
try return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
{ }
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
}
catch (System.ArgumentOutOfRangeException e)
{
//files might contain bad data, e.g. see #868. Fall back to MinValue
Kp2aLog.Log("Failed to read date from file.");
return DateTime.MinValue;
}
}
else else
{ {
string str = ReadString(xr); string str = ReadString(xr);

View File

@@ -581,7 +581,7 @@ namespace KeePassLib.Serialization
return vEntries; */ return vEntries; */
PwDatabase pd = new PwDatabase(); PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), ""); pd.New(new IOConnectionInfo(), new CompositeKey());
KdbxFile f = new KdbxFile(pd); KdbxFile f = new KdbxFile(pd);
f.Load(msData, KdbxFormat.PlainXml, null); f.Load(msData, KdbxFormat.PlainXml, null);

View File

@@ -1048,7 +1048,7 @@ namespace KeePassLib.Serialization
return true; */ return true; */
PwDatabase pd = new PwDatabase(); PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), ""); pd.New(new IOConnectionInfo(), new CompositeKey());
PwGroup pg = pd.RootGroup; PwGroup pg = pd.RootGroup;
if (pg == null) { Debug.Assert(false); return false; } if (pg == null) { Debug.Assert(false); return false; }

View File

@@ -23,7 +23,6 @@ using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Security; using System.Security;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
@@ -127,8 +126,8 @@ namespace KeePassLib.Serialization
/// </summary> /// </summary>
private const uint FileVersion32 = 0x00040000; private const uint FileVersion32 = 0x00040000;
public const uint FileVersion32_4 = 0x00040000; // First of 4.x series internal const uint FileVersion32_4 = 0x00040000; // First of 4.x series
public const uint FileVersion32_3 = 0x00030001; // Old format 3.1 internal const uint FileVersion32_3 = 0x00030001; // Old format 3.1
private const uint FileVersionCriticalMask = 0xFFFF0000; private const uint FileVersionCriticalMask = 0xFFFF0000;
@@ -373,22 +372,16 @@ namespace KeePassLib.Serialization
{ {
if(m_uForceVersion != 0) return m_uForceVersion; if(m_uForceVersion != 0) return m_uForceVersion;
// See also KeePassKdb2x3.Export (KDBX 3.1 export module) // See also KeePassKdb2x3.Export (KDBX 3.1 export module)
uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max();
uint minRequiredVersion = Math.Max(minVersionForKeys, m_uFileVersion); //don't save a version lower than what we read AesKdf kdfAes = new AesKdf();
AesKdf kdfAes = new AesKdf();
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
return Math.Max(FileVersion32, minRequiredVersion); return FileVersion32;
if(m_pwDatabase.PublicCustomData.Count > 0) if(m_pwDatabase.PublicCustomData.Count > 0)
return Math.Max(FileVersion32, minRequiredVersion); return FileVersion32;
bool bCustomData = false;
bool bCustomData = false;
GroupHandler gh = delegate(PwGroup pg) GroupHandler gh = delegate(PwGroup pg)
{ {
if(pg == null) { Debug.Assert(false); return true; } if(pg == null) { Debug.Assert(false); return true; }
@@ -403,10 +396,9 @@ namespace KeePassLib.Serialization
}; };
gh(m_pwDatabase.RootGroup); gh(m_pwDatabase.RootGroup);
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
if(bCustomData) if(bCustomData) return FileVersion32;
return Math.Max(FileVersion32, minRequiredVersion);
return Math.Max(FileVersion32_3, minRequiredVersion); ; // KDBX 3.1 is sufficient return FileVersion32_3; // KDBX 3.1 is sufficient
} }
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey, private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,

View File

@@ -26,11 +26,11 @@ namespace KeePassLib.Serialization
/// <summary> /// <summary>
/// Determines whether the database pointed to by the specified ioc should be (de)serialised in default (xml) or protocol buffers format. /// Determines whether the database pointed to by the specified ioc should be (de)serialised in default (xml) or protocol buffers format.
/// </summary> /// </summary>
public static KdbxFormat GetFormatToUse(string fileExt) public static KdbxFormat GetFormatToUse(IOConnectionInfo ioc)
{ {
return fileExt.Equals(KdbpFile.FileNameExtension, StringComparison.OrdinalIgnoreCase) ? KdbxFormat.ProtocolBuffers : // If the filename ends in .kdbp, use ProtocolBuffers format.
(fileExt.Equals("xml", StringComparison.OrdinalIgnoreCase) ? KdbxFormat.PlainXml : KdbxFormat.Default); return UrlUtil.GetExtension(UrlUtil.GetFileName(ioc.Path)).Equals(KdbpFile.FileNameExtension, StringComparison.OrdinalIgnoreCase) ? KdbxFormat.ProtocolBuffers : KdbxFormat.Default;
} }
public static void WriteDocument(PwDatabase database, Stream stream, byte[] protectedStreamKey, byte[] hashOfHeader) public static void WriteDocument(PwDatabase database, Stream stream, byte[] protectedStreamKey, byte[] hashOfHeader)
{ {

View File

@@ -37,7 +37,7 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
public static class MemUtil public static class MemUtil
{ {
public static readonly byte[] EmptyByteArray = new byte[0]; internal static readonly byte[] EmptyByteArray = new byte[0];
private static readonly uint[] m_vSBox = new uint[256] { private static readonly uint[] m_vSBox = new uint[256] {
0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230, 0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,

View File

@@ -1734,24 +1734,5 @@ namespace KeePassLib.Utility
// behavior of Notepad (on Windows 10) // behavior of Notepad (on Windows 10)
return str.Replace('\0', ' '); return str.Replace('\0', ' ');
} }
internal static string RemoveWhiteSpace(string str)
{
if (str == null) { Debug.Assert(false); return string.Empty; }
int cc = str.Length;
if (cc == 0) return string.Empty;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cc; ++i)
{
char ch = str[i];
if (char.IsWhiteSpace(ch)) continue;
sb.Append(ch);
}
return sb.ToString();
}
} }
} }

View File

@@ -1,290 +0,0 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Serialization;
namespace KeePassLib.Utility
{
public static class XmlUtilEx
{
public static XmlDocument CreateXmlDocument()
{
XmlDocument d = new XmlDocument();
// .NET 4.5.2 and newer do not resolve external XML resources
// by default; for older .NET versions, we explicitly
// prevent resolving
d.XmlResolver = null; // Default in old .NET: XmlUrlResolver object
return d;
}
public static XmlReaderSettings CreateXmlReaderSettings()
{
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.CloseInput = false;
xrs.IgnoreComments = true;
xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true;
#if KeePassUAP
xrs.DtdProcessing = DtdProcessing.Prohibit;
#else
// Also see PrepMonoDev.sh script
xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
#endif
xrs.ValidationType = ValidationType.None;
xrs.XmlResolver = null;
return xrs;
}
public static XmlReader CreateXmlReader(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
return XmlReader.Create(s, CreateXmlReaderSettings());
}
public static XmlWriterSettings CreateXmlWriterSettings()
{
XmlWriterSettings xws = new XmlWriterSettings();
xws.CloseOutput = false;
xws.Encoding = StrUtil.Utf8;
xws.Indent = true;
xws.IndentChars = "\t";
xws.NewLineOnAttributes = false;
return xws;
}
public static XmlWriter CreateXmlWriter(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
return XmlWriter.Create(s, CreateXmlWriterSettings());
}
public static T Deserialize<T>(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
XmlSerializer xs = new XmlSerializer(typeof(T));
T t = default(T);
using(XmlReader xr = CreateXmlReader(s))
{
t = (T)xs.Deserialize(xr);
}
return t;
}
public static void Serialize<T>(Stream s, T t)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
XmlSerializer xs = new XmlSerializer(typeof(T));
using(XmlWriter xw = CreateXmlWriter(s))
{
xs.Serialize(xw, t);
}
}
internal static void Serialize<T>(Stream s, T t, bool bRemoveXsdXsi)
{
// One way to remove the "xsd" and "xsi" namespace declarations
// is to use an XmlSerializerNamespaces object containing only
// a ""/"" pair; this seems to work, but Microsoft's
// documentation explicitly states that it isn't supported:
// https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializernamespaces
// There are other, more complex ways, but these either rely on
// undocumented details or require the type T to be modified.
string str;
using(MemoryStream ms = new MemoryStream())
{
Serialize<T>(ms, t);
str = StrUtil.Utf8.GetString(ms.ToArray());
}
Func<string, string, bool> fFindPfx = delegate(string strText, string strSub)
{
int i = strText.IndexOf(strSub, StringComparison.Ordinal);
if(i < 0) return false;
if(i == 0) return true;
return char.IsWhiteSpace(strText[i - 1]);
};
if(bRemoveXsdXsi)
{
if(!fFindPfx(str, "xsd:") && !fFindPfx(str, "xsi:"))
{
Debug.Assert(str.IndexOf("xmlns:xsd") > 0);
str = str.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", string.Empty);
Debug.Assert(str.IndexOf("xmlns:xsd") < 0);
Debug.Assert(str.IndexOf("xmlns:xsi") > 0);
str = str.Replace(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", string.Empty);
Debug.Assert(str.IndexOf("xmlns:xsi") < 0);
}
else { Debug.Assert(false); } // "xsd"/"xsi" decl. may be required
}
MemUtil.Write(s, StrUtil.Utf8.GetBytes(str));
}
#if DEBUG
internal static void ValidateXml(string strXml, bool bReplaceStdEntities)
{
if(strXml == null) throw new ArgumentNullException("strXml");
if(strXml.Length == 0) { Debug.Assert(false); return; }
string str = strXml;
if(bReplaceStdEntities)
str = str.Replace("&nbsp;", "&#160;");
XmlDocument d = new XmlDocument();
d.LoadXml(str);
}
#endif
internal static XPathNodeIterator FindNodes(PwDatabase pd, string strXPath,
IStatusLogger sl, out XmlDocument xd)
{
if(pd == null) throw new ArgumentNullException("pd");
if(strXPath == null) { Debug.Assert(false); strXPath = string.Empty; }
KdbxFile kdbx = new KdbxFile(pd);
byte[] pbXml;
using(MemoryStream ms = new MemoryStream())
{
kdbx.Save(ms, null, KdbxFormat.PlainXml, sl);
pbXml = ms.ToArray();
}
string strXml = StrUtil.Utf8.GetString(pbXml);
xd = CreateXmlDocument();
xd.LoadXml(strXml);
XPathNavigator xpNav = xd.CreateNavigator();
return xpNav.Select(strXPath);
// XPathExpression xpExpr = xpNav.Compile(strXPath);
// xpExpr.SetContext(new XuXsltContext());
// return xpNav.Select(xpExpr);
}
/* private sealed class XuFnMatches : IXsltContextFunction
{
private readonly XPathResultType[] m_vArgTypes = new XPathResultType[] {
XPathResultType.String, XPathResultType.String, XPathResultType.String
};
public XPathResultType[] ArgTypes { get { return m_vArgTypes; } }
public int Maxargs { get { return 3; } }
public int Minargs { get { return 2; } }
public XPathResultType ReturnType { get { return XPathResultType.Boolean; } }
private static string GetArgString(object[] args, int i, string strDefault)
{
if(args == null) { Debug.Assert(false); return strDefault; }
if(i >= args.Length) return strDefault;
object o = args[i];
if(o == null) return strDefault;
XPathNodeIterator it = (o as XPathNodeIterator);
if(it != null) o = it.Current.Value;
return (o.ToString() ?? strDefault);
}
public object Invoke(XsltContext xsltContext, object[] args,
XPathNavigator docContext)
{
string strInput = GetArgString(args, 0, string.Empty);
string strPattern = GetArgString(args, 1, string.Empty);
string strFlags = GetArgString(args, 2, null);
RegexOptions ro = RegexOptions.None;
if(!string.IsNullOrEmpty(strFlags))
{
if(strFlags.IndexOf('s') >= 0) ro |= RegexOptions.Singleline;
if(strFlags.IndexOf('m') >= 0) ro |= RegexOptions.Multiline;
if(strFlags.IndexOf('i') >= 0) ro |= RegexOptions.IgnoreCase;
if(strFlags.IndexOf('x') >= 0) ro |= RegexOptions.IgnorePatternWhitespace;
}
return Regex.IsMatch(strInput, strPattern, ro);
}
}
private sealed class XuXsltContext : XsltContext
{
public override bool Whitespace { get { return false; } }
public override int CompareDocument(string baseUri, string nextbaseUri)
{
return string.CompareOrdinal(baseUri, nextbaseUri);
}
public override bool PreserveWhitespace(XPathNavigator node)
{
return false;
}
public override IXsltContextFunction ResolveFunction(string prefix,
string name, XPathResultType[] ArgTypes)
{
if(prefix != "kp") { Debug.Assert(false); return null; }
if(name == "matches") return new XuFnMatches();
Debug.Assert(false);
return null;
}
public override IXsltContextVariable ResolveVariable(string prefix,
string name)
{
Debug.Assert(false);
return null;
}
} */
}
}

View File

@@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using keepass2android.Io;
using KeePassLib;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
namespace keepass2android
{
public class ElementAndDatabaseId
{
private const char Separator = '+';
public ElementAndDatabaseId(Database db, IStructureItem element)
{
DatabaseId = db.IocAsHexString();
ElementIdString = element.Uuid.ToHexString();
}
public ElementAndDatabaseId(string fullId)
{
string[] parts = fullId.Split(Separator);
if (parts.Length != 2)
throw new Exception("Invalid full id " + fullId);
DatabaseId = parts[0];
ElementIdString = parts[1];
}
public string DatabaseId { get; set; }
public string ElementIdString { get; set; }
public PwUuid ElementId { get { return new PwUuid(MemUtil.HexStringToByteArray(ElementIdString));} }
public string FullId
{
get { return DatabaseId + Separator + ElementIdString; }
}
}
}

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Security; using System.Net.Security;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using Android.App; using Android.App;
@@ -10,8 +9,7 @@ using KeePassLib;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using keepass2android.Io; using keepass2android.Io;
using KeePassLib.Interfaces; #if !NoNet
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage; using Keepass2android.Javafilestorage;
#endif #endif
@@ -29,47 +27,37 @@ namespace keepass2android
} }
/// <summary> /// <summary>
/// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data /// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data
/// </summary> /// </summary>
/// This also contains methods which are UI specific and should be replacable for testing. /// This also contains methods which are UI specific and should be replacable for testing.
public interface IKp2aApp : ICertificateValidationHandler public interface IKp2aApp : ICertificateValidationHandler
{ {
/// <summary> /// <summary>
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock) /// Locks the currently open database, quicklocking if available (unless false is passed for allowQuickUnlock)
/// </summary> /// </summary>
void Lock(bool allowQuickUnlock, bool lockWasTriggeredByTimeout); void LockDatabase(bool allowQuickUnlock = true);
/// <summary>
/// Loads the specified data as the currently open database, as unlocked.
/// </summary>
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey,
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
/// <summary> /// <summary>
/// Loads the specified data as the currently open database, as unlocked. /// Returns the current database
/// </summary> /// </summary>
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent); Database GetDb();
/// <summary>
HashSet<PwGroup> DirtyGroups { get; } /// Tell the app that the file from ioc was opened with keyfile.
/// </summary>
void MarkAllGroupsAsDirty(); void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
/// <summary>
/// Returns the current database
/// </summary>
Database CurrentDb { get; }
IEnumerable<Database> OpenDatabases { get; }
void CloseDatabase(Database db);
Database FindDatabaseForElement(IStructureItem element);
/// <summary>
/// Tell the app that the file from ioc was opened with keyfile.
/// </summary>
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, bool updateTimestamp, string displayName = "");
/// <summary> /// <summary>
/// Creates a new database and returns it /// Creates a new database and returns it
/// </summary> /// </summary>
Database CreateNewDatabase(bool makeCurrent); Database CreateNewDatabase();
/// <summary> /// <summary>
/// Returns the user-displayable string identified by stringKey /// Returns the user-displayable string identified by stringKey
@@ -88,8 +76,7 @@ namespace keepass2android
EventHandler<DialogClickEventArgs> yesHandler, EventHandler<DialogClickEventArgs> yesHandler,
EventHandler<DialogClickEventArgs> noHandler, EventHandler<DialogClickEventArgs> noHandler,
EventHandler<DialogClickEventArgs> cancelHandler, EventHandler<DialogClickEventArgs> cancelHandler,
Context ctx, Context ctx);
string messageSuffix = "");
/// <summary> /// <summary>
/// Asks the user the question "messageKey" with the options Yes/No/Cancel, but the yes/no strings can be selected freely, calls the handler corresponding to the answer. /// Asks the user the question "messageKey" with the options Yes/No/Cancel, but the yes/no strings can be selected freely, calls the handler corresponding to the answer.
@@ -99,8 +86,7 @@ namespace keepass2android
EventHandler<DialogClickEventArgs> yesHandler, EventHandler<DialogClickEventArgs> yesHandler,
EventHandler<DialogClickEventArgs> noHandler, EventHandler<DialogClickEventArgs> noHandler,
EventHandler<DialogClickEventArgs> cancelHandler, EventHandler<DialogClickEventArgs> cancelHandler,
Context ctx, Context ctx);
string messageSuffix = "");
/// <summary> /// <summary>
/// Returns a Handler object which can run tasks on the UI thread /// Returns a Handler object which can run tasks on the UI thread
@@ -123,12 +109,8 @@ namespace keepass2android
bool CheckForDuplicateUuids { get; } bool CheckForDuplicateUuids { get; }
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE #if !NoNet
ICertificateErrorHandler CertificateErrorHandler { get; } ICertificateErrorHandler CertificateErrorHandler { get; }
#endif #endif
} }
} }

View File

@@ -10,7 +10,6 @@ using Android.OS;
using Android.Provider; using Android.Provider;
using Java.IO; using Java.IO;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using KeePassLib.Utility;
using Console = System.Console; using Console = System.Console;
namespace keepass2android.Io namespace keepass2android.Io
@@ -78,16 +77,10 @@ namespace keepass2android.Io
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc) public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{ {
return UrlUtil.StripExtension( return "";
UrlUtil.GetFileName(ioc.Path)); }
}
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return UrlUtil.GetExtension(ioc.Path);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return false; return false;
} }
@@ -212,7 +205,8 @@ namespace keepass2android.Io
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc) public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{ {
return IoUtil.GetParentPath(ioc); //TODO: required for OTP Aux file retrieval
throw new NotImplementedException();
} }
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename) public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
@@ -270,7 +264,7 @@ namespace keepass2android.Io
} }
else return false; else return false;
} }
else return false; else throw new Exception("couldn't move to first result element: " + (cursor == null) + uri.ToString());
} }
catch (Exception e) catch (Exception e)
{ {
@@ -333,13 +327,12 @@ namespace keepass2android.Io
public void CommitWrite() public void CommitWrite()
{ {
ParcelFileDescriptor fileDescriptor = _ctx.ContentResolver.OpenFileDescriptor(Android.Net.Uri.Parse(_path), "rwt"); ParcelFileDescriptor fileDescriptor = _ctx.ContentResolver.OpenFileDescriptor(Android.Net.Uri.Parse(_path), "w");
using (var outputStream = new FileOutputStream(fileDescriptor.FileDescriptor)) using (var outputStream = new FileOutputStream(fileDescriptor.FileDescriptor))
{ {
byte[] data = _memoryStream.ToArray(); byte[] data = _memoryStream.ToArray();
outputStream.Write(data, 0, data.Length);
outputStream.Write(data);
outputStream.Close(); outputStream.Close();
} }
fileDescriptor.Close(); fileDescriptor.Close();

View File

@@ -12,10 +12,13 @@ using Android.Content;
using Android.Content.PM; using Android.Content.PM;
using Android.OS; using Android.OS;
using Android.Preferences; using Android.Preferences;
using Android.Support.V13.App;
using Android.Support.V4.App;
using Java.IO; using Java.IO;
using Android.Support.V4; using Java.Util;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using KeePassLib.Utility; using KeePassLib.Utility;
using ActivityCompat = Android.Support.V13.App.ActivityCompat;
using File = System.IO.File; using File = System.IO.File;
using FileNotFoundException = System.IO.FileNotFoundException; using FileNotFoundException = System.IO.FileNotFoundException;
using IOException = System.IO.IOException; using IOException = System.IO.IOException;
@@ -201,12 +204,7 @@ namespace keepass2android.Io
} }
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return UrlUtil.GetExtension(ioc.Path);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return (!ioc.IsLocalFile()) && (ioc.CredSaveMode != IOCredSaveMode.SaveCred); return (!ioc.IsLocalFile()) && (ioc.CredSaveMode != IOCredSaveMode.SaveCred);
} }
@@ -257,8 +255,7 @@ namespace keepass2android.Io
if (ioc.IsLocalFile()) if (ioc.IsLocalFile())
{ {
bool requiresPermission = !(ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath) bool requiresPermission = !(ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath)
|| ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath) || ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath));
|| ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath));
var extDirectory = activity.Activity.GetExternalFilesDir(null); var extDirectory = activity.Activity.GetExternalFilesDir(null);
if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath))) if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath)))

View File

@@ -65,28 +65,22 @@ namespace keepass2android.Io
protected readonly OfflineSwitchableFileStorage _cachedStorage; protected readonly OfflineSwitchableFileStorage _cachedStorage;
private readonly ICacheSupervisor _cacheSupervisor; private readonly ICacheSupervisor _cacheSupervisor;
private readonly string _legacyCacheDir; private readonly string _streamCacheDir;
private readonly string _cacheDir;
public CachingFileStorage(IFileStorage cachedStorage, Context cacheDirContext, ICacheSupervisor cacheSupervisor) public CachingFileStorage(IFileStorage cachedStorage, string cacheDir, ICacheSupervisor cacheSupervisor)
{ {
_cachedStorage = new OfflineSwitchableFileStorage(cachedStorage); _cachedStorage = new OfflineSwitchableFileStorage(cachedStorage);
_cacheSupervisor = cacheSupervisor; _cacheSupervisor = cacheSupervisor;
_legacyCacheDir = cacheDirContext.CacheDir.Path + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator; _streamCacheDir = cacheDir + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator;
if (!Directory.Exists(_legacyCacheDir)) if (!Directory.Exists(_streamCacheDir))
Directory.CreateDirectory(_legacyCacheDir); Directory.CreateDirectory(_streamCacheDir);
_cacheDir = IoUtil.GetInternalDirectory(cacheDirContext).Path + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator; }
if (!Directory.Exists(_cacheDir))
Directory.CreateDirectory(_cacheDir);
}
public void ClearCache() public void ClearCache()
{ {
IoUtil.DeleteDir(new Java.IO.File(_legacyCacheDir), true); IoUtil.DeleteDir(new Java.IO.File(_streamCacheDir), true);
IoUtil.DeleteDir(new Java.IO.File(_cacheDir), true); }
}
public IEnumerable<string> SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } } public IEnumerable<string> SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } }
@@ -111,23 +105,15 @@ namespace keepass2android.Io
{ {
SHA256Managed sha256 = new SHA256Managed(); SHA256Managed sha256 = new SHA256Managed();
string iocAsHexString = MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())))+".cache"; string iocAsHexString = MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())))+".cache";
if (File.Exists(_legacyCacheDir + iocAsHexString)) return _streamCacheDir + iocAsHexString;
return _legacyCacheDir + iocAsHexString;
return _cacheDir + iocAsHexString;
} }
public bool IsCached(IOConnectionInfo ioc) public bool IsCached(IOConnectionInfo ioc)
{ {
bool result = File.Exists(CachedFilePath(ioc)) return File.Exists(CachedFilePath(ioc))
&& File.Exists(VersionFilePath(ioc)) && File.Exists(VersionFilePath(ioc))
&& File.Exists(BaseVersionFilePath(ioc)); && File.Exists(BaseVersionFilePath(ioc));
}
Kp2aLog.Log(ioc.GetDisplayName() + " isCached = " + result);
return result;
}
public void Delete(IOConnectionInfo ioc) public void Delete(IOConnectionInfo ioc)
{ {
@@ -182,9 +168,7 @@ namespace keepass2android.Io
if (!IsCached(ioc)) if (!IsCached(ioc))
throw; throw;
#if DEBUG Kp2aLog.Log("couldn't open from remote " + ioc.Path);
Kp2aLog.Log("couldn't open from remote " + ioc.Path);
#endif
Kp2aLog.Log(ex.ToString()); Kp2aLog.Log(ex.ToString());
_cacheSupervisor.CouldntOpenFromRemote(ioc, ex); _cacheSupervisor.CouldntOpenFromRemote(ioc, ex);
@@ -361,7 +345,57 @@ namespace keepass2android.Io
private class CachedWriteTransaction: IWriteTransaction private class CachedWriteTransaction: IWriteTransaction
{ {
private class CachedWriteMemoryStream : MemoryStream
{
private readonly IOConnectionInfo ioc;
private readonly CachingFileStorage _cachingFileStorage;
private readonly bool _useFileTransaction;
private bool _closed;
public CachedWriteMemoryStream(IOConnectionInfo ioc, CachingFileStorage cachingFileStorage, bool useFileTransaction)
{
this.ioc = ioc;
_cachingFileStorage = cachingFileStorage;
_useFileTransaction = useFileTransaction;
}
public override void Close()
{
if (_closed) return;
//write file to cache:
//(note: this might overwrite local changes. It's assumed that a sync operation or check was performed before
string hash;
using (var hashingStream = new HashingStreamEx(File.Create(_cachingFileStorage.CachedFilePath(ioc)), true, new SHA256Managed()))
{
Position = 0;
CopyTo(hashingStream);
hashingStream.Close();
hash = MemUtil.ByteArrayToHexString(hashingStream.Hash);
}
File.WriteAllText(_cachingFileStorage.VersionFilePath(ioc), hash);
//update file on remote. This might overwrite changes there as well, see above.
Position = 0;
if (_cachingFileStorage.IsCached(ioc))
{
//if the file already is in the cache, it's ok if writing to remote fails.
_cachingFileStorage.TryUpdateRemoteFile(this, ioc, _useFileTransaction, hash);
}
else
{
//if not, we don't accept a failure (e.g. invalid credentials would always remain a problem)
_cachingFileStorage.UpdateRemoteFile(this, ioc, _useFileTransaction, hash);
}
base.Close();
_closed = true;
}
}
private readonly IOConnectionInfo _ioc; private readonly IOConnectionInfo _ioc;
private readonly bool _useFileTransaction; private readonly bool _useFileTransaction;
@@ -395,48 +429,17 @@ namespace keepass2android.Io
public Stream OpenFile() public Stream OpenFile()
{ {
_memoryStream = new MemoryStream(); _memoryStream = new CachedWriteMemoryStream(_ioc, _cachingFileStorage, _useFileTransaction);
return _memoryStream; return _memoryStream;
} }
public void CommitWrite() public void CommitWrite()
{ {
//the transaction is committed in the stream's Close
_committed = true; _committed = true;
_memoryStream.Close();
//write file to cache:
//(note: this might overwrite local changes. It's assumed that a sync operation or check was performed before
byte[] output = _memoryStream.ToArray();
string hash;
using (var hashingStream = new HashingStreamEx(File.Create(_cachingFileStorage.CachedFilePath(_ioc)), true, new SHA256Managed()))
{
hashingStream.Write(output, 0, output.Length);
hashingStream.Close();
hash = MemUtil.ByteArrayToHexString(hashingStream.Hash);
}
File.WriteAllText(_cachingFileStorage.VersionFilePath(_ioc), hash);
//create another memory stream which is open for reading again
MemoryStream openMemStream = new MemoryStream(output);
//update file on remote. This might overwrite changes there as well, see above.
if (_cachingFileStorage.IsCached(_ioc))
{
//if the file already is in the cache, it's ok if writing to remote fails.
_cachingFileStorage.TryUpdateRemoteFile(openMemStream, _ioc, _useFileTransaction, hash);
}
else
{
//if not, we don't accept a failure (e.g. invalid credentials would always remain a problem)
_cachingFileStorage.UpdateRemoteFile(openMemStream, _ioc, _useFileTransaction, hash);
}
openMemStream.Dispose();
} }
} }
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
@@ -452,12 +455,7 @@ namespace keepass2android.Io
return _cachedStorage.GetFilenameWithoutPathAndExt(ioc); return _cachedStorage.GetFilenameWithoutPathAndExt(ioc);
} }
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return _cachedStorage.GetFileExtension(ioc);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return _cachedStorage.RequiresCredentials(ioc); return _cachedStorage.RequiresCredentials(ioc);
} }
@@ -597,15 +595,11 @@ namespace keepass2android.Io
public string GetBaseVersionHash(IOConnectionInfo ioc) public string GetBaseVersionHash(IOConnectionInfo ioc)
{ {
string hash = File.ReadAllText(BaseVersionFilePath(ioc)); return File.ReadAllText(BaseVersionFilePath(ioc));
Kp2aLog.Log(ioc.GetDisplayName() + " baseVersionHash = " + hash); }
return hash;
}
public string GetLocalVersionHash(IOConnectionInfo ioc) public string GetLocalVersionHash(IOConnectionInfo ioc)
{ {
string hash = File.ReadAllText(VersionFilePath(ioc)); return File.ReadAllText(VersionFilePath(ioc));
Kp2aLog.Log(ioc.GetDisplayName() + " localVersionHash = " + hash);
return hash;
} }
public bool HasLocalChanges(IOConnectionInfo ioc) public bool HasLocalChanges(IOConnectionInfo ioc)
{ {

View File

@@ -2,12 +2,12 @@ namespace keepass2android.Io
{ {
public partial class DropboxFileStorage public partial class DropboxFileStorage
{ {
private const string AppKey = "dummy"; private const string AppKey = "";
private const string AppSecret = "dummy"; private const string AppSecret = "";
} }
public partial class DropboxAppFolderFileStorage public partial class DropboxAppFolderFileStorage
{ {
private const string AppKey = "dummy"; private const string AppKey = "";
private const string AppSecret = "dummy"; private const string AppSecret = "";
} }
} }

View File

@@ -88,13 +88,11 @@ namespace keepass2android.Io
IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction); IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc); string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc);
string GetFileExtension(IOConnectionInfo ioc); /// <summary>
/// Returns true if the the given ioc must be filled with username/password
/// <summary> /// </summary>
/// Returns true if the the given ioc must be filled with username/password bool RequiresCredentials(IOConnectionInfo ioc);
/// </summary>
bool RequiresCredentials(IOConnectionInfo ioc);
/// <summary> /// <summary>
/// Creates the directory described by ioc /// Creates the directory described by ioc

View File

@@ -128,12 +128,10 @@ namespace keepass2android.Io
} }
//creates a local ioc where the sourceIoc can be stored to //creates a local ioc where the sourceIoc can be stored to
public static IOConnectionInfo GetInternalIoc(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app) public static IOConnectionInfo GetInternalIoc(IOConnectionInfo sourceIoc, Context ctx)
{ {
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(ctx); Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(ctx);
var filestorage = app.GetFileStorage(sourceIoc); string targetPath = UrlUtil.GetFileName(sourceIoc.Path);
string targetPath = filestorage.GetFilenameWithoutPathAndExt(sourceIoc);
targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray()); targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
if (targetPath == "") if (targetPath == "")
targetPath = "internal"; targetPath = "internal";
@@ -155,7 +153,7 @@ namespace keepass2android.Io
public static IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app) public static IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app)
{ {
var targetIoc = GetInternalIoc(sourceIoc, ctx, app); var targetIoc = GetInternalIoc(sourceIoc, ctx);
IoUtil.Copy(targetIoc, sourceIoc, app); IoUtil.Copy(targetIoc, sourceIoc, app);

View File

@@ -177,12 +177,7 @@ namespace keepass2android.Io
_jfs.GetFilename(IocToPath(ioc))); _jfs.GetFilename(IocToPath(ioc)));
} }
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return UrlUtil.GetExtension(ioc.Path);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return false; return false;
} }
@@ -238,6 +233,7 @@ namespace keepass2android.Io
public FileDescription GetFileDescription(IOConnectionInfo ioc) public FileDescription GetFileDescription(IOConnectionInfo ioc)
{ {
Kp2aLog.Log("GetFileDescription "+ioc.Path);
try try
{ {
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc))); return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
@@ -306,9 +302,7 @@ namespace keepass2android.Io
public void OnResume(IFileStorageSetupActivity activity) public void OnResume(IFileStorageSetupActivity activity)
{ {
#if DEBUG
Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path); Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path);
#endif
_jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity)); _jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity));
} }
@@ -372,4 +366,4 @@ namespace keepass2android.Io
} }
} }
#endif #endif
} }

View File

@@ -3,12 +3,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.FtpClient;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using Android.Content; using Android.Content;
using Android.OS; using Android.OS;
using Android.Preferences; using Android.Preferences;
using FluentFTP;
using KeePassLib; using KeePassLib;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using KeePassLib.Utility; using KeePassLib.Utility;
@@ -17,6 +17,73 @@ namespace keepass2android.Io
{ {
public class NetFtpFileStorage: IFileStorage public class NetFtpFileStorage: IFileStorage
{ {
class RetryConnectFtpClient : FtpClient
{
protected override FtpClient CloneConnection()
{
RetryConnectFtpClient conn = new RetryConnectFtpClient();
conn.m_isClone = true;
foreach (PropertyInfo prop in GetType().GetProperties())
{
object[] attributes = prop.GetCustomAttributes(typeof(FtpControlConnectionClone), true);
if (attributes != null && attributes.Length > 0)
{
prop.SetValue(conn, prop.GetValue(this, null), null);
}
}
// always accept certficate no matter what because if code execution ever
// gets here it means the certificate on the control connection object being
// cloned was already accepted.
conn.ValidateCertificate += new FtpSslValidation(
delegate(FtpClient obj, FtpSslValidationEventArgs e)
{
e.Accept = true;
});
return conn;
}
private static T DoInRetryLoop<T>(Func<T> func)
{
double timeout = 30.0;
double timePerRequest = 1.0;
var startTime = DateTime.Now;
while (true)
{
var attemptStartTime = DateTime.Now;
try
{
return func();
}
catch (System.Net.Sockets.SocketException e)
{
if ((e.ErrorCode != 10061) || (DateTime.Now > startTime.AddSeconds(timeout)))
{
throw;
}
double secondsSinceAttemptStart = (DateTime.Now - attemptStartTime).TotalSeconds;
if (secondsSinceAttemptStart < timePerRequest)
{
Thread.Sleep(TimeSpan.FromSeconds(timePerRequest - secondsSinceAttemptStart));
}
}
}
}
public override void Connect()
{
DoInRetryLoop(() =>
{
base.Connect();
return true;
}
);
}
}
public struct ConnectionSettings public struct ConnectionSettings
{ {
public FtpEncryptionMode EncryptionMode {get; set; } public FtpEncryptionMode EncryptionMode {get; set; }
@@ -80,8 +147,9 @@ namespace keepass2android.Io
public NetFtpFileStorage(Context context, ICertificateValidationHandler app) public NetFtpFileStorage(Context context, ICertificateValidationHandler app)
{ {
_app = app; _app = app;
traceStream = new MemoryStream(); traceStream = new MemoryStream();
FtpTrace.AddListener(new System.Diagnostics.TextWriterTraceListener(traceStream));
} }
@@ -104,9 +172,9 @@ namespace keepass2android.Io
{ {
using (FtpClient client = GetClient(ioc)) using (FtpClient client = GetClient(ioc))
{ {
string localPath = IocToLocalPath(ioc); string localPath = IocToUri(ioc).PathAndQuery;
if (client.DirectoryExists(localPath)) if (client.DirectoryExists(localPath))
client.DeleteDirectory(localPath); client.DeleteDirectory(localPath, true);
else else
client.DeleteFile(localPath); client.DeleteFile(localPath);
} }
@@ -137,8 +205,7 @@ namespace keepass2android.Io
{ {
var settings = ConnectionSettings.FromIoc(ioc); var settings = ConnectionSettings.FromIoc(ioc);
FtpClient client = new FtpClient(); FtpClient client = new RetryConnectFtpClient();
client.RetryAttempts = 3;
if ((settings.Username.Length > 0) || (settings.Password.Length > 0)) if ((settings.Username.Length > 0) || (settings.Password.Length > 0))
client.Credentials = new NetworkCredential(settings.Username, settings.Password); client.Credentials = new NetworkCredential(settings.Username, settings.Password);
else else
@@ -183,22 +250,20 @@ namespace keepass2android.Io
path = path.Substring(settings.Length + 1); path = path.Substring(settings.Length + 1);
} }
Kp2aLog.Log("FTP: IocToUri out = " + scheme + "://" + path); return new Uri(scheme + "://" + path);
return new Uri(scheme + "://" + path);
} }
private string IocPathFromUri(IOConnectionInfo baseIoc, string uri) private string IocPathFromUri(IOConnectionInfo baseIoc, Uri uri)
{ {
string basePath = baseIoc.Path; string basePath = baseIoc.Path;
int schemeLength = basePath.IndexOf("://", StringComparison.Ordinal); int schemeLength = basePath.IndexOf("://", StringComparison.Ordinal);
string scheme = basePath.Substring(0, schemeLength); string scheme = basePath.Substring(0, schemeLength);
basePath = basePath.Substring(schemeLength + 3); basePath = basePath.Substring(schemeLength + 3);
string baseSettings = basePath.Substring(0, basePath.IndexOf(ConnectionSettings.SettingsPostFix, StringComparison.Ordinal)); string baseSettings = basePath.Substring(0, basePath.IndexOf(ConnectionSettings.SettingsPostFix, StringComparison.Ordinal));
basePath = basePath.Substring(baseSettings.Length+1); basePath = basePath.Substring(baseSettings.Length+1);
string baseHost = basePath.Substring(0, basePath.IndexOf("/", StringComparison.Ordinal)); string baseHost = basePath.Substring(0, basePath.IndexOf("/", StringComparison.Ordinal));
string result = scheme + "://" + baseSettings + ConnectionSettings.SettingsPostFix + baseHost + uri; //TODO does this contain Query? return scheme + "://" + baseSettings + ConnectionSettings.SettingsPostFix + baseHost + uri.AbsolutePath; //TODO does this contain Query?
return result; }
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
@@ -216,12 +281,9 @@ namespace keepass2android.Io
try try
{ {
using (var cl = GetClient(ioc)) using (var cl = GetClient(ioc))
{ {
var memStream = new MemoryStream(); return cl.OpenRead(IocToUri(ioc).PathAndQuery, FtpDataType.Binary, 0);
cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0).CopyTo(memStream); }
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
}
} }
catch (FtpCommandException ex) catch (FtpCommandException ex)
{ {
@@ -252,12 +314,7 @@ namespace keepass2android.Io
UrlUtil.GetFileName(ioc.Path)); UrlUtil.GetFileName(ioc.Path));
} }
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return UrlUtil.GetExtension(ioc.Path);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return false; return false;
} }
@@ -268,7 +325,7 @@ namespace keepass2android.Io
{ {
using (var client = GetClient(ioc)) using (var client = GetClient(ioc))
{ {
client.CreateDirectory(IocToLocalPath(GetFilePath(ioc, newDirName))); client.CreateDirectory(IocToUri(GetFilePath(ioc, newDirName)).PathAndQuery);
} }
} }
catch (FtpCommandException ex) catch (FtpCommandException ex)
@@ -277,19 +334,14 @@ namespace keepass2android.Io
} }
} }
public static string IocToLocalPath(IOConnectionInfo ioc) public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
return WebUtility.UrlDecode(IocToUri(ioc).PathAndQuery);
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{ {
try try
{ {
using (var client = GetClient(ioc)) using (var client = GetClient(ioc))
{ {
List<FileDescription> files = new List<FileDescription>(); List<FileDescription> files = new List<FileDescription>();
foreach (FtpListItem item in client.GetListing(IocToLocalPath(ioc), foreach (FtpListItem item in client.GetListing(IocToUri(ioc).PathAndQuery,
FtpListOption.Modify | FtpListOption.Size | FtpListOption.DerefLinks)) FtpListOption.Modify | FtpListOption.Size | FtpListOption.DerefLinks))
{ {
@@ -303,7 +355,7 @@ namespace keepass2android.Io
DisplayName = item.Name, DisplayName = item.Name,
IsDirectory = true, IsDirectory = true,
LastModified = item.Modified, LastModified = item.Modified,
Path = IocPathFromUri(ioc, item.FullName) Path = IocPathFromUri(ioc, new Uri(item.FullName))
}); });
break; break;
case FtpFileSystemObjectType.File: case FtpFileSystemObjectType.File:
@@ -314,7 +366,7 @@ namespace keepass2android.Io
DisplayName = item.Name, DisplayName = item.Name,
IsDirectory = false, IsDirectory = false,
LastModified = item.Modified, LastModified = item.Modified,
Path = IocPathFromUri(ioc, item.FullName), Path = IocPathFromUri(ioc, new Uri(item.FullName)),
SizeInBytes = item.Size SizeInBytes = item.Size
}); });
break; break;
@@ -339,10 +391,10 @@ namespace keepass2android.Io
//is it very inefficient to connect for each description? //is it very inefficient to connect for each description?
using (FtpClient client = GetClient(ioc)) using (FtpClient client = GetClient(ioc))
{ {
var uri = IocToUri(ioc);
string path = IocToLocalPath(ioc); string path = uri.PathAndQuery;
if (!client.FileExists(path) && (!client.DirectoryExists(path))) if (!client.FileExists(path) && (!client.DirectoryExists(path)))
throw new FileNotFoundException(); throw new FileNotFoundException();
var fileDesc = new FileDescription() var fileDesc = new FileDescription()
@@ -454,7 +506,7 @@ namespace keepass2android.Io
{ {
using (var client = GetClient(ioc)) using (var client = GetClient(ioc))
{ {
return client.OpenWrite(IocToLocalPath(ioc)); return client.OpenWrite(IocToUri(ioc).PathAndQuery);
} }
} }
@@ -523,7 +575,7 @@ namespace keepass2android.Io
{ {
_client = _fileStorage.GetClient(_ioc, false); _client = _fileStorage.GetClient(_ioc, false);
_stream = _client.OpenWrite(NetFtpFileStorage.IocToLocalPath(_iocTemp)); _stream = _client.OpenWrite(NetFtpFileStorage.IocToUri(_iocTemp).PathAndQuery);
return _stream; return _stream;
} }
catch (FtpCommandException ex) catch (FtpCommandException ex)
@@ -538,11 +590,22 @@ namespace keepass2android.Io
{ {
Android.Util.Log.Debug("NETFTP","connected: " + _client.IsConnected.ToString()); Android.Util.Log.Debug("NETFTP","connected: " + _client.IsConnected.ToString());
_stream.Close(); _stream.Close();
_stream.Dispose(); Android.Util.Log.Debug("NETFTP", "connected: " + _client.IsConnected.ToString());
_client.GetReply();
_client.MoveFile(NetFtpFileStorage.IocToLocalPath(_iocTemp), //make sure target file does not exist:
NetFtpFileStorage.IocToLocalPath(_ioc)); //try
{
if (_client.FileExists(NetFtpFileStorage.IocToUri(_ioc).PathAndQuery))
_client.DeleteFile(NetFtpFileStorage.IocToUri(_ioc).PathAndQuery);
}
//catch (FtpCommandException)
{
//TODO get a new clien? might be stale
}
_client.Rename(NetFtpFileStorage.IocToUri(_iocTemp).PathAndQuery,
NetFtpFileStorage.IocToUri(_ioc).PathAndQuery);
} }
catch (FtpCommandException ex) catch (FtpCommandException ex)

View File

@@ -78,12 +78,7 @@ namespace keepass2android.Io
return _baseStorage.GetFilenameWithoutPathAndExt(ioc); return _baseStorage.GetFilenameWithoutPathAndExt(ioc);
} }
public string GetFileExtension(IOConnectionInfo ioc) public bool RequiresCredentials(IOConnectionInfo ioc)
{
return _baseStorage.GetFileExtension(ioc);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{ {
return _baseStorage.RequiresCredentials(ioc); return _baseStorage.RequiresCredentials(ioc);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +0,0 @@
namespace keepass2android.Io.ItemLocation
{
public abstract class OneDrive2PrefixContainer
{
public abstract string Onedrive2ProtocolId { get; }
public string Onedrive2Prefix { get { return Onedrive2ProtocolId + "://"; } }
}
//for permissions including all my files and all shared files
public class OneDrive2FullPrefixContainer : OneDrive2PrefixContainer
{
public override string Onedrive2ProtocolId { get { return "onedrive2_full"; }}
}
//for permissions including all my files
public class OneDrive2MyFilesPrefixContainer : OneDrive2PrefixContainer
{
public override string Onedrive2ProtocolId { get { return "onedrive2_myfiles"; } }
}
//for permissions to app folder only
public class OneDrive2AppFolderPrefixContainer : OneDrive2PrefixContainer
{
public override string Onedrive2ProtocolId { get { return "onedrive2_appfolder"; } }
}
}

View File

@@ -1,23 +0,0 @@
using Android.Content;
#if !EXCLUDE_JAVAFILESTORAGE
namespace keepass2android.Io
{
public partial class PCloudFileStorage: JavaFileStorage
{
private const string ClientId = "CkRWTQXY6Lm";
public PCloudFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId), app)
{
}
public override bool UserShouldBackup
{
get { return false; }
}
}
}
#endif

View File

@@ -5,8 +5,8 @@ namespace keepass2android.Io
{ {
public class SftpFileStorage: JavaFileStorage public class SftpFileStorage: JavaFileStorage
{ {
public SftpFileStorage(Context ctx, IKp2aApp app) : public SftpFileStorage(IKp2aApp app) :
base(new Keepass2android.Javafilestorage.SftpStorage(ctx.ApplicationContext), app) base(new Keepass2android.Javafilestorage.SftpStorage(), app)
{ {
} }

View File

@@ -9,14 +9,14 @@ using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Views; using Android.Views;
using Android.Widget; using Android.Widget;
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE #if !NoNet
using Keepass2android.Javafilestorage; using Keepass2android.Javafilestorage;
#endif #endif
using KeePassLib.Serialization; using KeePassLib.Serialization;
namespace keepass2android.Io namespace keepass2android.Io
{ {
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE #if !NoNet
public class WebDavFileStorage: JavaFileStorage public class WebDavFileStorage: JavaFileStorage
{ {
public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app) public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app)
@@ -30,8 +30,7 @@ namespace keepass2android.Io
yield return "http"; yield return "http";
yield return "https"; yield return "https";
yield return "owncloud"; yield return "owncloud";
yield return "nextcloud"; }
}
} }
public override bool UserShouldBackup public override bool UserShouldBackup
@@ -39,15 +38,12 @@ namespace keepass2android.Io
get { return true; } get { return true; }
} }
public static string owncloudPrefix = "owncloud://"; public static string Owncloud2Webdav(string owncloudUrl)
public static string nextcloudPrefix = "nextcloud://";
public static string Owncloud2Webdav(string owncloudUrl, string prefix)
{ {
string owncloudPrefix = "owncloud://";
if (owncloudUrl.StartsWith(prefix)) if (owncloudUrl.StartsWith(owncloudPrefix))
{ {
owncloudUrl = owncloudUrl.Substring(prefix.Length); owncloudUrl = owncloudUrl.Substring(owncloudPrefix.Length);
} }
if (!owncloudUrl.Contains("://")) if (!owncloudUrl.Contains("://"))
owncloudUrl = "https://" + owncloudUrl; owncloudUrl = "https://" + owncloudUrl;

View File

@@ -12,8 +12,8 @@
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion> <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<NuGetPackageImportStamp> <NuGetPackageImportStamp>
</NuGetPackageImportStamp> </NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
@@ -22,7 +22,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;_EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants> <DefineConstants>DEBUG;EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode> <AndroidLinkMode>None</AndroidLinkMode>
@@ -31,10 +31,9 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;NoNet;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<JavaMaximumHeapSize>4G</JavaMaximumHeapSize>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'">
@@ -54,15 +53,44 @@
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Xamarin.Android.Arch.Core.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Core.Common.1.0.0\lib\MonoAndroid80\Xamarin.Android.Arch.Core.Common.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.0.1\lib\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Common.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Arch.Lifecycle.Runtime, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.0.0\lib\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Runtime.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Annotations, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Annotations.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Compat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Compat.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Core.UI.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Core.UI.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.Utils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Core.Utils.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Core.Utils.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Fragment, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Fragment.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Fragment.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Media.Compat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.Media.Compat.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.Media.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v13, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Android.Support.v13.26.1.0.1\lib\MonoAndroid80\Xamarin.Android.Support.v13.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="database\CheckDatabaseForChanges.cs" /> <Compile Include="database\CheckDatabaseForChanges.cs" />
<Compile Include="database\edit\AddTemplateEntries.cs" /> <Compile Include="database\edit\AddTemplateEntries.cs" />
<Compile Include="database\edit\CopyEntry.cs" /> <Compile Include="database\edit\CopyEntry.cs" />
<Compile Include="database\edit\DeleteMultipleItemsFromOneDatabase.cs" /> <Compile Include="database\edit\DeleteMultipleItems.cs" />
<Compile Include="database\edit\EditGroup.cs" /> <Compile Include="database\edit\EditGroup.cs" />
<Compile Include="database\edit\MoveElements.cs" /> <Compile Include="database\edit\MoveElements.cs" />
<Compile Include="database\KdbDatabaseFormat.cs" /> <Compile Include="database\KdbDatabaseFormat.cs" />
@@ -74,27 +102,15 @@
<Compile Include="DataExchange\Formats\KeePassKdb2x.cs" /> <Compile Include="DataExchange\Formats\KeePassKdb2x.cs" />
<Compile Include="DataExchange\Formats\KeePassXml2x.cs" /> <Compile Include="DataExchange\Formats\KeePassXml2x.cs" />
<Compile Include="DataExchange\PwExportInfo.cs" /> <Compile Include="DataExchange\PwExportInfo.cs" />
<Compile Include="ElementAndDatabaseId.cs" />
<Compile Include="Io\AndroidContentStorage.cs" /> <Compile Include="Io\AndroidContentStorage.cs" />
<Compile Include="Io\BuiltInFileStorage.cs" /> <Compile Include="Io\BuiltInFileStorage.cs" />
<Compile Include="Io\CachingFileStorage.cs" /> <Compile Include="Io\CachingFileStorage.cs" />
<Compile Include="Io\DropboxFileStorage.cs" />
<Compile Include="Io\DropboxFileStorageKeys.cs" />
<Compile Include="Io\FileDescription.cs" /> <Compile Include="Io\FileDescription.cs" />
<Compile Include="Io\FileStorageSetupActivity.cs" /> <Compile Include="Io\FileStorageSetupActivity.cs" />
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" /> <Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
<Compile Include="Io\GDriveFileStorage.cs" />
<Compile Include="Io\IFileStorage.cs" /> <Compile Include="Io\IFileStorage.cs" />
<Compile Include="Io\IoUtil.cs" /> <Compile Include="Io\IoUtil.cs" />
<Compile Include="Io\JavaFileStorage.cs" />
<Compile Include="Io\NetFtpFileStorage.cs" />
<Compile Include="Io\OfflineSwitchableFileStorage.cs" /> <Compile Include="Io\OfflineSwitchableFileStorage.cs" />
<Compile Include="Io\OneDrive2FileStorage.cs" />
<Compile Include="Io\OneDrive2PrefixContainer.cs" />
<Compile Include="Io\PCloudFileStorage.cs" />
<Compile Include="Io\SftpFileStorage.cs" />
<Compile Include="Io\OneDriveFileStorage.cs" />
<Compile Include="Io\WebDavFileStorage.cs" />
<Compile Include="IProgressDialog.cs" /> <Compile Include="IProgressDialog.cs" />
<Compile Include="PreferenceKey.cs" /> <Compile Include="PreferenceKey.cs" />
<Compile Include="SelectStorageLocationActivityBase.cs" /> <Compile Include="SelectStorageLocationActivityBase.cs" />
@@ -103,15 +119,15 @@
<Compile Include="database\edit\ActionOnFinish.cs" /> <Compile Include="database\edit\ActionOnFinish.cs" />
<Compile Include="database\edit\AddEntry.cs" /> <Compile Include="database\edit\AddEntry.cs" />
<Compile Include="database\edit\AddGroup.cs" /> <Compile Include="database\edit\AddGroup.cs" />
<Compile Include="database\edit\CreateDB.cs" /> <Compile Include="database\edit\CreateDb.cs" />
<Compile Include="database\edit\DeleteEntry.cs" /> <Compile Include="database\edit\DeleteEntry.cs" />
<Compile Include="database\edit\DeleteGroup.cs" /> <Compile Include="database\edit\DeleteGroup.cs" />
<Compile Include="database\edit\DeleteRunnable.cs" /> <Compile Include="database\edit\DeleteRunnable.cs" />
<Compile Include="database\edit\FileOnFinish.cs" /> <Compile Include="database\edit\FileOnFinish.cs" />
<Compile Include="database\edit\LoadDB.cs" /> <Compile Include="database\edit\LoadDb.cs" />
<Compile Include="database\edit\OnFinish.cs" /> <Compile Include="database\edit\OnFinish.cs" />
<Compile Include="database\edit\RunnableOnFinish.cs" /> <Compile Include="database\edit\RunnableOnFinish.cs" />
<Compile Include="database\edit\SaveDB.cs" /> <Compile Include="database\edit\SaveDb.cs" />
<Compile Include="database\edit\SetPassword.cs" /> <Compile Include="database\edit\SetPassword.cs" />
<Compile Include="database\edit\UpdateEntry.cs" /> <Compile Include="database\edit\UpdateEntry.cs" />
<Compile Include="IKp2aApp.cs" /> <Compile Include="IKp2aApp.cs" />
@@ -130,14 +146,6 @@
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" /> <Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj">
<Project>{3c0f7fe5-639f-4422-a087-8b26cf862d1b}</Project>
<Name>AndroidFileChooserBinding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>
</ProjectReference>
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj"> <ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project> <Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
<Name>KeePassLib2Android</Name> <Name>KeePassLib2Android</Name>
@@ -146,10 +154,6 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project> <Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name> <Name>KP2AKdbLibraryBinding</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj">
<Project>{2db80c77-d46f-4970-b967-e9ffa9b2ac2e}</Project>
<Name>PCloudBindings</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj"> <ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project> <Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name> <Name>TwofishCipher</Name>
@@ -159,125 +163,34 @@
<Folder Include="Resources\" /> <Folder Include="Resources\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>31.3.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.21.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph.Auth">
<Version>1.0.0-preview.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Client">
<Version>4.8.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Annotations">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Collections">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.UI">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomView">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Fragment">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Interpolator">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Loader">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Print">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v13">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v4">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.ViewPager">
<Version>28.0.0.3</Version>
</PackageReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Xamarin.Android.Support.Annotations.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Annotations.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Annotations.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Annotations.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Annotations.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Annotations.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Annotations.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Annotations.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Core.Common.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Core.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Core.Common.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Core.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.0.1\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.0.1\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Runtime.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Compat.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Compat.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Core.UI.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.UI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Core.UI.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.UI.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Core.Utils.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.Utils.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Core.Utils.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.Utils.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Fragment.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Fragment.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Fragment.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Fragment.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.Media.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Media.Compat.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.Media.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Media.Compat.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Android.Support.v13.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v13.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Android.Support.v13.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v13.targets'))" />
</Target>
<Import Project="..\packages\Xamarin.Android.Arch.Core.Common.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Core.Common.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Core.Common.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Core.Common.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.0.1\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Common.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Common.1.0.1\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Common.targets')" />
<Import Project="..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Runtime.targets" Condition="Exists('..\packages\Xamarin.Android.Arch.Lifecycle.Runtime.1.0.0\build\MonoAndroid80\Xamarin.Android.Arch.Lifecycle.Runtime.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Core.UI.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Core.UI.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Core.Utils.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Core.Utils.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Fragment.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Fragment.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Media.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Media.Compat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v13.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v13.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v13.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v13.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View File

@@ -30,12 +30,8 @@ namespace keepass2android
readonly IKp2aApp _app; readonly IKp2aApp _app;
private readonly Handler _handler; private readonly Handler _handler;
private string _message = ""; private string _message = "";
private string _submessage;
public String SubMessage => _submessage; public ProgressDialogStatusLogger() {
public String Message => _message;
public ProgressDialogStatusLogger() {
} }
@@ -52,8 +48,7 @@ namespace keepass2android
public void UpdateMessage (String message) public void UpdateMessage (String message)
{ {
Kp2aLog.Log("status message: " + message); _message = message;
_message = message;
if ( _app!= null && _progressDialog != null && _handler != null ) { if ( _app!= null && _progressDialog != null && _handler != null ) {
_handler.Post(() => {_progressDialog.SetMessage(message); } ); _handler.Post(() => {_progressDialog.SetMessage(message); } );
} }
@@ -61,8 +56,6 @@ namespace keepass2android
public void UpdateSubMessage(String submessage) public void UpdateSubMessage(String submessage)
{ {
Kp2aLog.Log("status submessage: " + submessage);
_submessage = submessage;
if (_app != null && _progressDialog != null && _handler != null) if (_app != null && _progressDialog != null && _handler != null)
{ {
_handler.Post(() => _handler.Post(() =>

View File

@@ -25,118 +25,39 @@ namespace keepass2android
/// <summary> /// <summary>
/// Class to run a task while a progress dialog is shown /// Class to run a task while a progress dialog is shown
/// </summary> /// </summary>
public class ProgressTask public class ProgressTask {
{
//for handling Activity recreation situations, we need access to the currently active task. It must hold that there is no more than one active task.
private static ProgressTask _currentTask = null;
public static void SetNewActiveActivity(Activity activeActivity)
{
if (_currentTask != null)
{
_currentTask.ActiveActivity = activeActivity;
}
}
public static void RemoveActiveActivity(Activity activity)
{
if ((_currentTask != null) && (_currentTask._activeActivity == activity))
_currentTask.ActiveActivity = null;
}
public Activity ActiveActivity
{
get { return _activeActivity; }
private set
{
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
{
_previouslyActiveActivity = _activeActivity;
}
_activeActivity = value;
if (_task != null)
_task.ActiveActivity = _activeActivity;
if (_activeActivity != null)
{
SetupProgressDialog(_app);
_progressDialog.Show();
}
}
}
public Activity PreviouslyActiveActivity
{
get { return _previouslyActiveActivity; }
}
private readonly Handler _handler; private readonly Handler _handler;
private readonly RunnableOnFinish _task; private readonly RunnableOnFinish _task;
private IProgressDialog _progressDialog; private readonly IProgressDialog _progressDialog;
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private Thread _thread; private Thread _thread;
private Activity _activeActivity, _previouslyActiveActivity;
private ProgressDialogStatusLogger _progressDialogStatusLogger;
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task) public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) {
{
_activeActivity = activity;
_task = task; _task = task;
_handler = app.UiThreadHandler; _handler = app.UiThreadHandler;
_app = app; _app = app;
SetupProgressDialog(app); // Show process dialog
_progressDialog = app.CreateProgressDialog(ctx);
// Set code to run when this is finished _progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
_task.OnFinishToRun = new AfterTask(activity, task.OnFinishToRun, _handler, this); _progressDialog.SetMessage("Initializing...");
_task.SetStatusLogger(_progressDialogStatusLogger); // Set code to run when this is finished
_task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog);
_task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog));
} }
private void SetupProgressDialog(IKp2aApp app) public void Run() {
{ // Show process dialog
string currentMessage = "Initializing..."; _progressDialog.Show();
string currentSubmessage = "";
if (_progressDialogStatusLogger != null)
{
currentMessage = _progressDialogStatusLogger.Message;
currentSubmessage = _progressDialogStatusLogger.SubMessage;
}
if (_progressDialog != null)
{
var pd = _progressDialog;
app.UiThreadHandler.Post(() =>
{
pd.Dismiss();
});
}
// Show process dialog
_progressDialog = app.CreateProgressDialog(_activeActivity);
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
_progressDialogStatusLogger = new ProgressDialogStatusLogger(_app, _handler, _progressDialog);
_progressDialogStatusLogger.UpdateMessage(currentMessage);
_progressDialogStatusLogger.UpdateSubMessage(currentSubmessage);
}
public void Run(bool allowOverwriteCurrentTask = false)
{
if ((!allowOverwriteCurrentTask) && (_currentTask != null))
throw new Exception("Cannot start another ProgressTask while ProgressTask is already running! " + _task.GetType().Name + "/" + _currentTask._task.GetType().Name);
_currentTask = this;
// Show process dialog
_progressDialog.Show();
// Start Thread to Run task // Start Thread to Run task
_thread = new Thread(_task.Run); _thread = new Thread(_task.Run);
_thread.Start(); _thread.Start();
} }
public void JoinWorkerThread() public void JoinWorkerThread()
@@ -145,11 +66,11 @@ namespace keepass2android
} }
private class AfterTask : OnFinish { private class AfterTask : OnFinish {
readonly ProgressTask _progressTask; readonly IProgressDialog _progressDialog;
public AfterTask (Activity activity, OnFinish finish, Handler handler, ProgressTask pt): base(activity, finish, handler) public AfterTask (OnFinish finish, Handler handler, IProgressDialog pd): base(finish, handler)
{ {
_progressTask = pt; _progressDialog = pd;
} }
public override void Run() { public override void Run() {
@@ -158,22 +79,17 @@ namespace keepass2android
if (Handler != null) //can be null in tests if (Handler != null) //can be null in tests
{ {
// Remove the progress dialog // Remove the progress dialog
Handler.Post(delegate Handler.Post(delegate { _progressDialog.Dismiss(); });
{
_progressTask._progressDialog.Dismiss();
});
} }
else else
{ {
_progressTask._progressDialog.Dismiss(); _progressDialog.Dismiss();
} }
_currentTask = null;
} }
} }
} }
} }

View File

@@ -23,7 +23,7 @@ namespace keepass2android
/// <summary> /// <summary>
/// EqualityComparer implementation to compare PwGroups based on their Id /// EqualityComparer implementation to compare PwGroups based on their Id
/// </summary> /// </summary>
public class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup> class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
{ {
#region IEqualityComparer implementation #region IEqualityComparer implementation
public bool Equals (PwGroup x, PwGroup y) public bool Equals (PwGroup x, PwGroup y)

File diff suppressed because it is too large Load Diff

View File

@@ -72,8 +72,8 @@ namespace keepass2android
SearchParameters sp = SearchParameters.None; SearchParameters sp = SearchParameters.None;
sp.SearchInUrls = true; sp.SearchInUrls = true;
sp.SearchString = url; sp.SearchString = url;
if(sp.RegularExpression) // Validate regular expression if(sp.RegularExpression) // Validate regular expression
{ {
new Regex(sp.SearchString); new Regex(sp.SearchString);
} }
@@ -103,10 +103,8 @@ namespace keepass2android
PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) {IsVirtual = true}; PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) {IsVirtual = true};
if (String.IsNullOrWhiteSpace(host)) if (String.IsNullOrWhiteSpace(host))
return pgResults; return pgResults;
foreach (PwEntry entry in database.EntriesById.Values) foreach (PwEntry entry in database.Entries.Values)
{ {
if (!entry.GetSearchingEnabled())
continue;
string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField); string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField);
otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References)); otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References));
String otherHost = ExtractHost(otherUrl); String otherHost = ExtractHost(otherUrl);

View File

@@ -86,9 +86,6 @@ namespace keepass2android
ReadOnlyReason_PreKitKat, ReadOnlyReason_PreKitKat,
ReadOnlyReason_ReadOnlyFlag, ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat, ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup, ReadOnlyReason_LocalBackup
Ok,
cancel,
FileNotFound
} }
} }

View File

@@ -25,7 +25,9 @@ using KeePass.Util.Spr;
using KeePassLib; using KeePassLib;
using KeePassLib.Collections; using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Delegates; using KeePassLib.Delegates;
using KeePassLib.Security;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePass.Util namespace KeePass.Util
@@ -87,8 +89,41 @@ namespace KeePass.Util
return str; return str;
} }
*/ */
private static string ReplaceHmacOtpPlaceholder(string strText,
SprContext ctx)
{
PwEntry pe = ctx.Entry;
PwDatabase pd = ctx.Database;
if((pe == null) || (pd == null)) return strText;
public static bool EntriesHaveSameParent(PwObjectList<PwEntry> v) string str = strText;
const string strHmacOtpPlh = @"{HMACOTP}";
if(str.IndexOf(strHmacOtpPlh, StrUtil.CaseIgnoreCmp) >= 0)
{
const string strKeyField = "HmacOtp-Secret";
const string strCounterField = "HmacOtp-Counter";
byte[] pbSecret = StrUtil.Utf8.GetBytes(pe.Strings.ReadSafe(
strKeyField));
string strCounter = pe.Strings.ReadSafe(strCounterField);
ulong uCounter;
ulong.TryParse(strCounter, out uCounter);
string strValue = HmacOtp.Generate(pbSecret, uCounter, 6, false, -1);
pe.Strings.Set(strCounterField, new ProtectedString(false,
(uCounter + 1).ToString()));
pd.Modified = true;
str = StrUtil.ReplaceCaseInsensitive(str, strHmacOtpPlh, strValue);
}
return str;
}
public static bool EntriesHaveSameParent(PwObjectList<PwEntry> v)
{ {
if(v == null) { Debug.Assert(false); return true; } if(v == null) { Debug.Assert(false); return true; }
if(v.UCount == 0) return true; if(v.UCount == 0) return true;

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Identity.Client" publicKeyToken="0a613f4dd989e8ae" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -18,8 +18,8 @@ namespace keepass2android
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
public CheckDatabaseForChanges(Activity context, IKp2aApp app, OnFinish finish) public CheckDatabaseForChanges(Context context, IKp2aApp app, OnFinish finish)
: base(context, finish) : base(finish)
{ {
_context = context; _context = context;
_app = app; _app = app;
@@ -29,7 +29,7 @@ namespace keepass2android
{ {
try try
{ {
IOConnectionInfo ioc = _app.CurrentDb.Ioc; IOConnectionInfo ioc = _app.GetDb().Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc); IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (fileStorage is CachingFileStorage) if (fileStorage is CachingFileStorage)
{ {
@@ -49,7 +49,7 @@ namespace keepass2android
hashingRemoteStream.CopyTo(remoteData); hashingRemoteStream.CopyTo(remoteData);
hashingRemoteStream.Close(); hashingRemoteStream.Close();
if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash)) if (!MemUtil.ArraysEqual(_app.GetDb().KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
{ {
_app.TriggerReload(_context); _app.TriggerReload(_context);
Finish(true); Finish(true);

View File

@@ -21,12 +21,12 @@ using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using Android.Content;
using Java.Lang; using Java.Lang;
using KeePassLib; using KeePassLib;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using keepass2android.Io; using keepass2android.Io;
using KeePassLib.Interfaces;
using KeePassLib.Utility; using KeePassLib.Utility;
using Exception = System.Exception; using Exception = System.Exception;
using String = System.String; using String = System.String;
@@ -34,23 +34,27 @@ using String = System.String;
namespace keepass2android namespace keepass2android
{ {
public class Database public class Database {
{
public HashSet<IStructureItem> Elements = new HashSet<IStructureItem>();
public Dictionary<PwUuid, PwGroup> GroupsById = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer()); public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
public Dictionary<PwUuid, PwEntry> EntriesById = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer()); public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
public HashSet<PwGroup> Dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
public PwGroup Root; public PwGroup Root;
public PwDatabase KpDatabase; public PwDatabase KpDatabase;
public IOConnectionInfo Ioc public IOConnectionInfo Ioc
{ {
get get
{ {
return KpDatabase == null ? null : KpDatabase.IOConnectionInfo;
return KpDatabase?.IOConnectionInfo;
} }
} }
/// <summary>
/// Information about the last opened entry. Includes the entry but also transformed fields.
/// </summary>
public PwEntryOutput LastOpenedEntry { get; set; }
/// <summary> /// <summary>
/// if an OTP key was used, this property tells the location of the OTP auxiliary file. /// if an OTP key was used, this property tells the location of the OTP auxiliary file.
/// Must be set after loading. /// Must be set after loading.
@@ -70,14 +74,31 @@ namespace keepass2android
_app = app; _app = app;
CanWrite = true; //default CanWrite = true; //default
} }
private bool _loaded;
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default); private bool _reloadRequested;
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
public bool ReloadRequested { get; set; } public bool ReloadRequested
{
get { return _reloadRequested; }
set { _reloadRequested = value; }
}
public bool DidOpenFileChange() public bool Loaded {
get { return _loaded;}
set { _loaded = value; }
}
public bool DidOpenFileChange()
{ {
if (Loaded == false)
{
return false;
}
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion); return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
} }
@@ -92,20 +113,32 @@ namespace keepass2android
Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo); Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo);
var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo); var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat); PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat);
LastFileVersion = fileVersion; try
{
LastFileVersion = fileVersion;
status.UpdateSubMessage(""); status.UpdateSubMessage("");
Root = pwDatabase.RootGroup; Root = pwDatabase.RootGroup;
PopulateGlobals(Root); PopulateGlobals(Root);
KpDatabase = pwDatabase; KpDatabase = pwDatabase;
SearchHelper = new SearchDbHelper(app); SearchHelper = new SearchDbHelper(app);
_databaseFormat = databaseFormat; _databaseFormat = databaseFormat;
CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo); CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo);
Loaded = true;
}
catch (Exception)
{
Clear();
throw;
}
} }
/// <summary> /// <summary>
@@ -185,9 +218,10 @@ namespace keepass2android
} }
public void SaveData() { public void SaveData(Context ctx) {
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions))) KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
{ {
DatabaseFormat.Save(KpDatabase, trans.OpenFile()); DatabaseFormat.Save(KpDatabase, trans.OpenFile());
@@ -206,18 +240,14 @@ namespace keepass2android
{ {
if (checkForDuplicateUuids) if (checkForDuplicateUuids)
{ {
if (EntriesById.ContainsKey(e.Uuid)) if (Entries.ContainsKey(e.Uuid))
{ {
throw new DuplicateUuidsException("Same UUID for entries '"+EntriesById[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'."); throw new DuplicateUuidsException("Same UUID for entries '"+Entries[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'.");
} }
} }
EntriesById [e.Uuid] = e; Entries [e.Uuid] = e;
Elements.Add(e);
} }
GroupsById[currentGroup.Uuid] = currentGroup;
Elements.Add(currentGroup);
foreach (PwGroup g in childGroups) foreach (PwGroup g in childGroups)
{ {
if (checkForDuplicateUuids) if (checkForDuplicateUuids)
@@ -229,6 +259,7 @@ namespace keepass2android
} }
* */ * */
} }
Groups[g.Uuid] = g;
PopulateGlobals(g); PopulateGlobals(g);
} }
} }
@@ -236,15 +267,33 @@ namespace keepass2android
{ {
PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids); PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids);
} }
public void Clear() {
_loaded = false;
Groups.Clear();
Entries.Clear();
Dirty.Clear();
DrawableFactory.Clear();
Root = null;
KpDatabase = null;
CanWrite = true;
_reloadRequested = false;
OtpAuxFileIoc = null;
LastOpenedEntry = null;
}
public void MarkAllGroupsAsDirty() {
foreach ( PwGroup group in Groups.Values ) {
Dirty.Add(group);
}
}
public void UpdateGlobals()
{
EntriesById.Clear();
GroupsById.Clear();
Elements.Clear();
PopulateGlobals(Root);
}
} }
[Serializable] [Serializable]

View File

@@ -216,16 +216,9 @@ namespace keepass2android
private DateTime JavaTimeToCSharp(long javatime) private DateTime JavaTimeToCSharp(long javatime)
{ {
try
{
var utcTime = new DateTime(1970, 1, 1).AddMilliseconds(javatime);
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, TimeZoneInfo.Local);
}
catch (ArgumentOutOfRangeException)
{
return DateTime.MinValue;
}
var utcTime = new DateTime(1970, 1, 1).AddMilliseconds(javatime);
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, TimeZoneInfo.Local);
} }
#endif #endif

View File

@@ -27,7 +27,7 @@ namespace keepass2android
} }
public byte[] HashOfLastStream { get; private set; } public byte[] HashOfLastStream { get; private set; }
public bool CanWrite { get { return _format != KdbxFormat.PlainXml; } } public bool CanWrite { get { return true; } }
public string SuccessMessage { get { return null; } } public string SuccessMessage { get { return null; } }
public void Save(PwDatabase kpDatabase, Stream stream) public void Save(PwDatabase kpDatabase, Stream stream)
{ {

View File

@@ -14,13 +14,13 @@ namespace keepass2android
public class PwEntryOutput public class PwEntryOutput
{ {
private readonly PwEntry _entry; private readonly PwEntry _entry;
private readonly Database _db; private readonly PwDatabase _db;
private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary(); private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
/// <summary> /// <summary>
/// Constructs the PwEntryOutput by replacing the placeholders /// Constructs the PwEntryOutput by replacing the placeholders
/// </summary> /// </summary>
public PwEntryOutput(PwEntry entry, Database db) public PwEntryOutput(PwEntry entry, PwDatabase db)
{ {
_entry = entry; _entry = entry;
_db = db; _db = db;
@@ -34,7 +34,7 @@ namespace keepass2android
string GetStringAndReplacePlaceholders(string key) string GetStringAndReplacePlaceholders(string key)
{ {
String value = Entry.Strings.ReadSafe(key); String value = Entry.Strings.ReadSafe(key);
value = SprEngine.Compile(value, new SprContext(Entry, _db.KpDatabase, SprCompileFlags.All)); value = SprEngine.Compile(value, new SprContext(Entry, _db, SprCompileFlags.All));
return value; return value;
} }

View File

@@ -11,12 +11,12 @@ namespace keepass2android
{ {
public class SynchronizeCachedDatabase: RunnableOnFinish public class SynchronizeCachedDatabase: RunnableOnFinish
{ {
private readonly Activity _context; private readonly Context _context;
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private SaveDb _saveDb; private SaveDb _saveDb;
public SynchronizeCachedDatabase(Activity context, IKp2aApp app, OnFinish finish) public SynchronizeCachedDatabase(Context context, IKp2aApp app, OnFinish finish)
: base(context, finish) : base(finish)
{ {
_context = context; _context = context;
_app = app; _app = app;
@@ -26,7 +26,7 @@ namespace keepass2android
{ {
try try
{ {
IOConnectionInfo ioc = _app.CurrentDb.Ioc; IOConnectionInfo ioc = _app.GetDb().Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc); IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (!(fileStorage is CachingFileStorage)) if (!(fileStorage is CachingFileStorage))
{ {
@@ -43,27 +43,23 @@ namespace keepass2android
try try
{ {
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash); remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
Kp2aLog.Log("Checking for file change. Current hash = " + hash);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile)); StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)); cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
Kp2aLog.Log("Checking for file change: file not found");
return; return;
} }
//check if remote file was modified: //check if remote file was modified:
var baseVersionHash = cachingFileStorage.GetBaseVersionHash(ioc); if (cachingFileStorage.GetBaseVersionHash(ioc) != hash)
Kp2aLog.Log("Checking for file change. baseVersionHash = " + baseVersionHash);
if (baseVersionHash != hash)
{ {
//remote file is modified //remote file is modified
if (cachingFileStorage.HasLocalChanges(ioc)) if (cachingFileStorage.HasLocalChanges(ioc))
{ {
//conflict! need to merge //conflict! need to merge
_saveDb = new SaveDb(_context, _app, new ActionOnFinish(ActiveActivity, (success, result, activity) => _saveDb = new SaveDb(_context, _app, new ActionOnFinish((success, result) =>
{ {
if (!success) if (!success)
{ {
@@ -74,12 +70,10 @@ namespace keepass2android
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
} }
_saveDb = null; _saveDb = null;
}), _app.CurrentDb, false, remoteData); }), false, remoteData);
_saveDb.Run(); _saveDb.Run();
_app.CurrentDb.UpdateGlobals(); _app.GetDb().MarkAllGroupsAsDirty();
_app.MarkAllGroupsAsDirty();
} }
else else
{ {
@@ -109,7 +103,6 @@ namespace keepass2android
} }
catch (Exception e) catch (Exception e)
{ {
Kp2aLog.LogUnexpectedError(e);
Finish(false, e.Message); Finish(false, e.Message);
} }

View File

@@ -16,40 +16,41 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
*/ */
using System; using System;
using Android.App;
using Android.OS; using Android.OS;
namespace keepass2android namespace keepass2android
{ {
public class ActionOnFinish: OnFinish public class ActionOnFinish: OnFinish
{ {
public delegate void ActionToPerformOnFinsh(bool success, String message, Activity activeActivity); public delegate void ActionToPerformOnFinsh(bool success, String message);
readonly ActionToPerformOnFinsh _actionToPerform; readonly ActionToPerformOnFinsh _actionToPerform;
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform) : base(activity, null, null) public ActionOnFinish(ActionToPerformOnFinsh actionToPerform) : base(null, null)
{ {
_actionToPerform = actionToPerform; _actionToPerform = actionToPerform;
} }
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform, OnFinish finish) : base(activity, finish) public ActionOnFinish(ActionToPerformOnFinsh actionToPerform, OnFinish finish) : base(finish)
{ {
_actionToPerform = actionToPerform; _actionToPerform = actionToPerform;
} }
//if set to true, the previously active active will be passed to ActionToPerformOnFinish instead null if no activity is on foreground public ActionOnFinish(ActionToPerformOnFinsh actionToPerform, Handler handler) : base(handler)
public bool AllowInactiveActivity { get; set; } {
_actionToPerform = actionToPerform;
}
public override void Run() public override void Run()
{ {
if (Message == null) if (Message == null)
Message = ""; Message = "";
if (Handler != null) if (Handler != null)
{ {
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);}); Handler.Post(() => {_actionToPerform(Success, Message);});
} }
else else
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity); _actionToPerform(Success, Message);
base.Run(); base.Run();
} }
} }

View File

@@ -15,7 +15,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>. along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/ */
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
@@ -24,28 +23,26 @@ namespace keepass2android
public class AddEntry : RunnableOnFinish { public class AddEntry : RunnableOnFinish {
protected Database Db protected Database Db
{ {
get { return _app.CurrentDb; } get { return _app.GetDb(); }
} }
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private readonly PwEntry _entry; private readonly PwEntry _entry;
private readonly PwGroup _parentGroup; private readonly PwGroup _parentGroup;
private readonly Activity _ctx; private readonly Context _ctx;
private readonly Database _db;
public static AddEntry GetInstance(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish, Database db) { return new AddEntry(ctx, app, entry, parentGroup, finish);
return new AddEntry(ctx, db, app, entry, parentGroup, finish);
} }
public AddEntry(Activity ctx, Database db, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) { protected AddEntry(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
_ctx = ctx; _ctx = ctx;
_db = db; _parentGroup = parentGroup;
_parentGroup = parentGroup;
_app = app; _app = app;
_entry = entry; _entry = entry;
_onFinishToRun = new AfterAdd(ctx, app.CurrentDb, entry, app,OnFinishToRun); _onFinishToRun = new AfterAdd(app.GetDb(), entry, OnFinishToRun);
} }
@@ -59,13 +56,10 @@ namespace keepass2android
{ {
_parentGroup.AddEntry(_entry, true); _parentGroup.AddEntry(_entry, true);
} }
// Add entry to global
_db.EntriesById[_entry.Uuid] = _entry; // Commit to disk
_db.Elements.Add(_entry); SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
// Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -73,13 +67,12 @@ namespace keepass2android
private class AfterAdd : OnFinish { private class AfterAdd : OnFinish {
private readonly Database _db; private readonly Database _db;
private readonly PwEntry _entry; private readonly PwEntry _entry;
private readonly IKp2aApp _app;
public AfterAdd(Activity activity, Database db, PwEntry entry, IKp2aApp app, OnFinish finish):base(activity, finish) { public AfterAdd(Database db, PwEntry entry, OnFinish finish):base(finish) {
_db = db; _db = db;
_entry = entry; _entry = entry;
_app = app;
} }
@@ -89,10 +82,11 @@ namespace keepass2android
PwGroup parent = _entry.ParentGroup; PwGroup parent = _entry.ParentGroup;
// Mark parent group dirty // Mark parent group dirty
_app.DirtyGroups.Add(parent); _db.Dirty.Add(parent);
// Add entry to global
_db.Entries[_entry.Uuid] = _entry;
} else } else
{ {
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges); StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/ */
using System; using System;
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
@@ -26,28 +25,25 @@ namespace keepass2android
public class AddGroup : RunnableOnFinish { public class AddGroup : RunnableOnFinish {
internal Database Db internal Database Db
{ {
get { return _app.CurrentDb; } get { return _app.GetDb(); }
} }
private IKp2aApp _app;
public IKp2aApp App { get => _app; }
private IKp2aApp _app;
private readonly String _name; private readonly String _name;
private readonly int _iconId; private readonly int _iconId;
private readonly PwUuid _groupCustomIconId; private readonly PwUuid _groupCustomIconId;
public PwGroup Group; internal PwGroup Group;
internal PwGroup Parent; internal PwGroup Parent;
protected bool DontSave; protected bool DontSave;
readonly Activity _ctx; readonly Context _ctx;
public static AddGroup GetInstance(Activity ctx, IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) { public static AddGroup GetInstance(Context ctx, IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) {
return new AddGroup(ctx, app, name, iconid, groupCustomIconId, parent, finish, dontSave); return new AddGroup(ctx, app, name, iconid, groupCustomIconId, parent, finish, dontSave);
} }
private AddGroup(Activity ctx, IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) private AddGroup(Context ctx, IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave)
: base(ctx, finish) : base(finish)
{ {
_ctx = ctx; _ctx = ctx;
_name = name; _name = name;
@@ -57,7 +53,7 @@ namespace keepass2android
DontSave = dontSave; DontSave = dontSave;
_app = app; _app = app;
_onFinishToRun = new AfterAdd(ctx, this, OnFinishToRun); _onFinishToRun = new AfterAdd(this, OnFinishToRun);
} }
@@ -70,11 +66,9 @@ namespace keepass2android
Group.CustomIconUuid = _groupCustomIconId; Group.CustomIconUuid = _groupCustomIconId;
} }
Parent.AddGroup(Group, true); Parent.AddGroup(Group, true);
_app.CurrentDb.GroupsById[Group.Uuid] = Group;
_app.CurrentDb.Elements.Add(Group);
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave); SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -82,7 +76,7 @@ namespace keepass2android
private class AfterAdd : OnFinish { private class AfterAdd : OnFinish {
readonly AddGroup _addGroup; readonly AddGroup _addGroup;
public AfterAdd(Activity activity, AddGroup addGroup,OnFinish finish): base(activity, finish) { public AfterAdd(AddGroup addGroup,OnFinish finish): base(finish) {
_addGroup = addGroup; _addGroup = addGroup;
} }
@@ -91,15 +85,13 @@ namespace keepass2android
if ( Success ) { if ( Success ) {
// Mark parent group dirty // Mark parent group dirty
_addGroup.App.DirtyGroups.Add(_addGroup.Parent); _addGroup.Db.Dirty.Add(_addGroup.Parent);
// Add group to global list // Add group to global list
_addGroup.Db.GroupsById[_addGroup.Group.Uuid] = _addGroup.Group; _addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
_addGroup.Db.Elements.Add(_addGroup.Group);
} else { } else {
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges); StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
_addGroup.Parent.Groups.Remove(_addGroup.Group); _addGroup.Parent.Groups.Remove(_addGroup.Group);
} }
base.Run(); base.Run();

View File

@@ -18,7 +18,6 @@ This file is part of Keepass2Android, Copyright 2016 Philipp Crocoll. This file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
using KeePassLib.Security; using KeePassLib.Security;
@@ -28,7 +27,7 @@ namespace keepass2android
{ {
public class AddTemplateEntries : RunnableOnFinish { public class AddTemplateEntries : RunnableOnFinish {
public class TemplateEntry class TemplateEntry
{ {
public UiStringKey Title { get; set; } public UiStringKey Title { get; set; }
public PwIcon Icon { get; set; } public PwIcon Icon { get; set; }
@@ -47,12 +46,11 @@ namespace keepass2android
void AddToEntry(IKp2aApp app, PwEntry entry, int position); void AddToEntry(IKp2aApp app, PwEntry entry, int position);
} }
public enum FieldType internal enum FieldType
{ {
Inline, ProtectedInline Inline, ProtectedInline
} }
internal enum SpecialFieldKey
public enum SpecialFieldKey
{ {
ExpDate, OverrideUrl, Tags ExpDate, OverrideUrl, Tags
} }
@@ -126,14 +124,14 @@ namespace keepass2android
protected Database Db protected Database Db
{ {
get { return _app.CurrentDb; } get { return _app.GetDb(); }
} }
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private readonly Activity _ctx; private readonly Context _ctx;
public AddTemplateEntries(Activity ctx, IKp2aApp app, OnFinish finish) public AddTemplateEntries(Context ctx, IKp2aApp app, OnFinish finish)
: base(ctx, finish) : base(finish)
{ {
_ctx = ctx; _ctx = ctx;
_app = app; _app = app;
@@ -141,7 +139,7 @@ namespace keepass2android
//_onFinishToRun = new AfterAdd(this, OnFinishToRun); //_onFinishToRun = new AfterAdd(this, OnFinishToRun);
} }
public static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>() static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
{ {
new TemplateEntry() new TemplateEntry()
{ {
@@ -286,23 +284,12 @@ namespace keepass2android
}; };
public static bool ContainsAllTemplates(Database db) public static bool ContainsAllTemplates(IKp2aApp app)
{ {
return TemplateEntries.All(t => return TemplateEntries.All(t => app.GetDb().Entries.ContainsKey(t.Uuid));
{
string hexId = t.Uuid.ToHexString();
return db.EntriesById.Any(kvp => kvp.Key.Equals(t.Uuid) ||
kvp.Value.Strings.ReadSafe(TemplateIdStringKey) == hexId);
});
} }
public static string TemplateIdStringKey public override void Run() {
{
get { return "KP2A_TemplateId"; }
}
public override void Run() {
StatusLogger.UpdateMessage(UiStringKey.AddingEntry); StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
List<PwEntry> addedEntries; List<PwEntry> addedEntries;
@@ -310,10 +297,10 @@ namespace keepass2android
if (addedEntries.Any()) if (addedEntries.Any())
{ {
_app.DirtyGroups.Add(templateGroup); _app.GetDb().Dirty.Add(templateGroup);
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun); SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -327,28 +314,26 @@ namespace keepass2android
} }
PwGroup templateGroup; PwGroup templateGroup;
if (!_app.CurrentDb.GroupsById.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup)) if (!_app.GetDb().Groups.TryGetValue(_app.GetDb().KpDatabase.EntryTemplatesGroup, out templateGroup))
{ {
//create template group //create template group
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder); templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
_app.CurrentDb.KpDatabase.RootGroup.AddGroup(templateGroup, true); _app.GetDb().KpDatabase.RootGroup.AddGroup(templateGroup, true);
_app.CurrentDb.KpDatabase.EntryTemplatesGroup = templateGroup.Uuid; _app.GetDb().KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
_app.CurrentDb.KpDatabase.EntryTemplatesGroupChanged = DateTime.Now; _app.GetDb().KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
_app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup); _app.GetDb().Dirty.Add(_app.GetDb().KpDatabase.RootGroup);
_app.CurrentDb.GroupsById[templateGroup.Uuid] = templateGroup; _app.GetDb().Groups[templateGroup.Uuid] = templateGroup;
_app.CurrentDb.Elements.Add(templateGroup);
} }
addedEntries = new List<PwEntry>(); addedEntries = new List<PwEntry>();
foreach (var template in TemplateEntries) foreach (var template in TemplateEntries)
{ {
if (_app.CurrentDb.EntriesById.ContainsKey(template.Uuid)) if (_app.GetDb().Entries.ContainsKey(template.Uuid))
continue; continue;
PwEntry entry = CreateEntry(template); PwEntry entry = CreateEntry(template);
templateGroup.AddEntry(entry, true); templateGroup.AddEntry(entry, true);
addedEntries.Add(entry); addedEntries.Add(entry);
_app.CurrentDb.EntriesById[entry.Uuid] = entry; _app.GetDb().Entries[entry.Uuid] = entry;
} }
return templateGroup; return templateGroup;
} }
@@ -373,7 +358,7 @@ namespace keepass2android
private readonly Database _db; private readonly Database _db;
private readonly List<PwEntry> _entries; private readonly List<PwEntry> _entries;
public AfterAdd(Activity activity, Database db, List<PwEntry> entries, OnFinish finish):base(activity, finish) { public AfterAdd(Database db, List<PwEntry> entries, OnFinish finish):base(finish) {
_db = db; _db = db;
_entries = entries; _entries = entries;
@@ -387,12 +372,8 @@ namespace keepass2android
base.Run(); base.Run();
} }
} }
public static bool IsTemplateId(PwUuid pwUuid)
{
return TemplateEntries.Any(te => te.Uuid.Equals(pwUuid));
}
} }
} }

View File

@@ -16,8 +16,8 @@ namespace keepass2android.database.edit
{ {
public class CopyEntry: AddEntry public class CopyEntry: AddEntry
{ {
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish, Database db) public CopyEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish)
: base(ctx, db, app, CreateCopy(entry, app), entry.ParentGroup, finish) : base(ctx, app, CreateCopy(entry, app), entry.ParentGroup, finish)
{ {
} }

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
using KeePassLib.Cryptography.KeyDerivation; using KeePassLib.Cryptography.KeyDerivation;
@@ -27,36 +26,36 @@ namespace keepass2android
{ {
public class CreateDb : RunnableOnFinish { public class CreateDb : RunnableOnFinish {
private readonly IOConnectionInfo _ioc;
private const ulong DefaultEncryptionRounds = PwDefs.DefaultKeyEncryptionRounds;
private readonly IOConnectionInfo _ioc;
private readonly bool _dontSave; private readonly bool _dontSave;
private readonly Activity _ctx; private readonly Context _ctx;
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private CompositeKey _key; private CompositeKey _key;
private readonly bool _makeCurrent;
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, bool makeCurrent): base(ctx, finish) { public CreateDb(IKp2aApp app, Context ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave): base(finish) {
_ctx = ctx; _ctx = ctx;
_ioc = ioc; _ioc = ioc;
_dontSave = dontSave; _dontSave = dontSave;
_makeCurrent = makeCurrent; _app = app;
_app = app;
} }
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key, bool makeCurrent) public CreateDb(IKp2aApp app, Context ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key)
: base(ctx, finish) : base(finish)
{ {
_ctx = ctx; _ctx = ctx;
_ioc = ioc; _ioc = ioc;
_dontSave = dontSave; _dontSave = dontSave;
_app = app; _app = app;
_key = key; _key = key;
_makeCurrent = makeCurrent;
} }
public override void Run() { public override void Run() {
StatusLogger.UpdateMessage(UiStringKey.progress_create); StatusLogger.UpdateMessage(UiStringKey.progress_create);
Database db = _app.CreateNewDatabase(_makeCurrent); Database db = _app.CreateNewDatabase();
db.KpDatabase = new KeePassLib.PwDatabase(); db.KpDatabase = new KeePassLib.PwDatabase();
@@ -65,7 +64,7 @@ namespace keepass2android
_key = new CompositeKey(); //use a temporary key which should be changed after creation _key = new CompositeKey(); //use a temporary key which should be changed after creation
} }
db.KpDatabase.New(_ioc, _key, _app.GetFileStorage(_ioc).GetFilenameWithoutPathAndExt(_ioc)); db.KpDatabase.New(_ioc, _key);
db.KpDatabase.KdfParameters = (new AesKdf()).GetDefaultParameters(); db.KpDatabase.KdfParameters = (new AesKdf()).GetDefaultParameters();
db.KpDatabase.Name = "Keepass2Android Password Database"; db.KpDatabase.Name = "Keepass2Android Password Database";
@@ -74,6 +73,7 @@ namespace keepass2android
// Set Database state // Set Database state
db.Root = db.KpDatabase.RootGroup; db.Root = db.KpDatabase.RootGroup;
db.Loaded = true;
db.SearchHelper = new SearchDbHelper(_app); db.SearchHelper = new SearchDbHelper(_app);
// Add a couple default groups // Add a couple default groups
@@ -87,14 +87,12 @@ namespace keepass2android
addTemplates.AddTemplates(out addedEntries); addTemplates.AddTemplates(out addedEntries);
// Commit changes // Commit changes
SaveDb save = new SaveDb(_ctx, _app, db, OnFinishToRun, _dontSave); SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
_onFinishToRun = null; _onFinishToRun = null;
save.Run(); save.Run();
db.UpdateGlobals();
} }
} }

View File

@@ -17,7 +17,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
@@ -29,9 +28,9 @@ namespace keepass2android
private readonly PwEntry _entry; private readonly PwEntry _entry;
private UiStringKey _statusMessage; private UiStringKey _statusMessage;
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) { public DeleteEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish):base(finish, app) {
Ctx = activiy; Ctx = ctx;
Db = app.FindDatabaseForElement(entry); Db = app.GetDb();
_entry = entry; _entry = entry;
} }
@@ -40,7 +39,7 @@ namespace keepass2android
{ {
get get
{ {
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup); return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
} }
} }

View File

@@ -17,7 +17,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Android.App;
using Android.Content; using Android.Content;
using KeePassLib; using KeePassLib;
@@ -29,10 +28,10 @@ namespace keepass2android
private PwGroup _group; private PwGroup _group;
protected bool DontSave; protected bool DontSave;
public DeleteGroup(Activity activity, IKp2aApp app, PwGroup group, OnFinish finish) public DeleteGroup(Context ctx, IKp2aApp app, PwGroup group, OnFinish finish)
: base(activity, finish, app) : base(finish, app)
{ {
SetMembers(activity, app, group, false); SetMembers(ctx, app, group, false);
} }
/* /*
public DeleteGroup(Context ctx, Database db, PwGroup group, Activity act, OnFinish finish, bool dontSave) public DeleteGroup(Context ctx, Database db, PwGroup group, Activity act, OnFinish finish, bool dontSave)
@@ -45,9 +44,9 @@ namespace keepass2android
SetMembers(ctx, db, group, null, dontSave); SetMembers(ctx, db, group, null, dontSave);
} }
*/ */
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave) private void SetMembers(Context ctx, IKp2aApp app, PwGroup group, bool dontSave)
{ {
base.SetMembers(activity, app.FindDatabaseForElement(group)); base.SetMembers(ctx, app.GetDb());
_group = group; _group = group;
DontSave = dontSave; DontSave = dontSave;
@@ -58,7 +57,7 @@ namespace keepass2android
{ {
get get
{ {
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_group); return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
} }
} }

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