Compare commits

...

120 Commits

Author SHA1 Message Date
J-Jamet
161923c808 Merge branch 'release/2.5.0.0beta8' 2018-04-06 20:29:26 +02:00
J-Jamet
d5a03424d0 Solve fab color 2018-04-06 20:27:33 +02:00
J-Jamet
3e87c1ab9d Change password layout 2018-04-06 19:39:58 +02:00
J-Jamet
a6046bc49a Add sorting by last access and by creation time 2018-04-06 19:02:31 +02:00
J-Jamet
db98f4b30c Remove db name for v3 2018-04-06 17:15:36 +02:00
J-Jamet
60eff63569 Add dialogs to save Db name and description 2018-04-06 16:51:25 +02:00
J-Jamet
b8e97ec53b Change rounds_fix_explanation 2018-04-06 08:43:33 +02:00
J-Jamet
c2b60b2268 Entry edit as menu, Launch in lowercase 2018-04-06 08:34:53 +02:00
J-Jamet
cac1f923cc Change url icon by launch icon 2018-04-06 08:06:37 +02:00
J-Jamet
b4ac0ef21f Move donation in menu 2018-04-06 07:56:57 +02:00
J-Jamet
8b85c22f25 Remove font 2018-04-05 20:31:27 +02:00
J-Jamet
582faab29d Base64Coder as dependency 2018-04-05 20:28:47 +02:00
J-Jamet
a9f6fa3441 commons-collections as dependency 2018-04-05 20:21:47 +02:00
J-Jamet
54740c1ba2 Change packages and solve dependencies 2018-04-05 20:11:08 +02:00
J-Jamet
94a8ecbdf1 GPL2 to GPL3 2018-04-05 18:41:49 +02:00
J-Jamet
46855e0b70 Merge branch 'feature/EncryptionSettings' into develop #9 2018-04-05 17:25:07 +02:00
J-Jamet
2d3eabe07e Update changelogs 2018-04-05 17:24:11 +02:00
J-Jamet
48bda000e9 Add database name, description and version, encapsulate db methods 2018-04-05 17:20:17 +02:00
J-Jamet
8aea6fa2da Remove keepassdroid assets 2018-04-05 13:26:00 +02:00
J-Jamet
c46aa0e5c8 remove .idea files from being tracked 2018-04-05 13:17:13 +02:00
J-Jamet
825d88014d Set Key Rounds for database V4 2018-04-04 20:37:23 +02:00
J-Jamet
b3ff38fb35 Get rounds from KdfParameters 2018-04-04 17:25:45 +02:00
J-Jamet
1e4deb2182 Refactor rounds 2018-04-04 14:42:58 +02:00
J-Jamet
d5acd04a19 Merge branch 'develop' into feature/EncryptionSettings 2018-04-04 13:38:48 +02:00
J-Jamet
fe73a951e3 Upgrade version 2018-04-04 13:38:05 +02:00
J-Jamet
415094154d Upgrade description 2018-04-04 13:31:07 +02:00
J-Jamet
3b88b0fea6 Keep long in DateToKDBX4 2018-04-03 13:49:23 +02:00
J-Jamet
d8e3d52f21 Catch OutOfMemoryError when writing 2018-04-03 13:07:05 +02:00
J-Jamet
8105f89088 New FileSystem screen 2018-03-31 16:29:34 +02:00
J-Jamet
90084ed2f7 Solve protected field display 2018-03-31 14:57:01 +02:00
J-Jamet
496725a8fd Add encryption settings 2018-03-30 21:04:33 +02:00
J-Jamet
72b0cdf0d7 Add changelogs 2018-03-30 16:07:37 +02:00
J-Jamet
a266d307a6 Change timeout settings 2018-03-30 16:05:47 +02:00
J-Jamet
f7fe414597 Hide custom entries protected #65 2018-03-30 15:18:58 +02:00
J-Jamet
5c1e9bd94f Patch to allow autofill in search #62 2018-03-30 14:03:43 +02:00
J-Jamet
747135afae Fix crash #69 2018-03-29 23:26:22 +02:00
J-Jamet
675efe3ab8 Replace anonymous fun by lambda 2018-03-29 23:12:16 +02:00
J-Jamet
02b6191e66 Merge branch 'feature/RefactorModel' into develop 2018-03-29 22:15:40 +02:00
J-Jamet
1e07d6a28d Solve field reference issues #61 (Was fix in part by refactoring) 2018-03-29 22:07:09 +02:00
J-Jamet
ab98f03ebf Fix ExpireDate issue for Database V3 2018-03-29 21:17:24 +02:00
J-Jamet
4aff5e3a06 Fix ExpireDate issue for Database V3 2018-03-29 17:24:32 +02:00
J-Jamet
3ad4e8efe7 #67 Add warning dialog for storage setting 2018-03-29 12:34:07 +02:00
J-Jamet
d04d7737c3 Change copy password summary 2018-03-29 10:28:45 +02:00
J-Jamet
8de52cb51e Solve default XML settings 2018-03-29 10:25:55 +02:00
J-Jamet
c8cb79726b Change search methods 2018-03-29 10:16:44 +02:00
J-Jamet
d51a227c1d Add accessors to Database 2018-03-29 09:55:32 +02:00
J-Jamet
94ed03ce35 Refactor Database, Add Type parameters, Refactor ExtraFields 2018-03-29 00:35:25 +02:00
J-Jamet
304a5e946d Merge branch 'develop' into ModelTypeParameter 2018-03-28 21:37:50 +02:00
J-Jamet
ff64b53580 Fix crash when database can't be saved 2018-03-28 21:30:44 +02:00
J-Jamet
9ece794f9a Add type parameter to PwObject 2018-03-28 14:33:00 +02:00
J-Jamet
b67dc22f10 Solve gradle compilation warning 2018-03-28 12:41:23 +02:00
J-Jamet
8a1a29caa8 Upgrade Android version dialog #49 2018-03-28 11:57:03 +02:00
J-Jamet
a8d07c3e82 Refactor entry search 2018-03-27 18:46:59 +02:00
J-Jamet
937135bb36 Solve bug #63 Empty Autofill View 2018-03-27 15:31:47 +02:00
J-Jamet
10c32266c2 Add accessors to PwDatabase 2018-03-26 16:04:38 +02:00
J-Jamet
ad45369442 Add color to notification 2018-03-26 13:14:52 +02:00
J-Jamet
1ca770fa72 Upgrade fastlane 2018-03-25 20:58:24 +02:00
J-Jamet
4acd11d2b2 Merge tag '2.5.0.0beta7' into develop
2.5.0.0beta7
2018-03-25 20:40:21 +02:00
J-Jamet
38c264e38d Merge branch 'release/2.5.0.0beta7' 2018-03-25 20:40:00 +02:00
J-Jamet
8da6b882fc Fix compilation 2018-03-25 20:23:54 +02:00
J-Jamet
6e03c2ebfc Upgrade changelogs 2018-03-25 20:10:53 +02:00
J-Jamet
a5cb5ed896 Temp Merge branch 'feature/RefactorModel' to correct serializable crash 2018-03-25 20:03:41 +02:00
J-Jamet
32bef7b099 Add constructors 2018-03-25 15:49:13 +02:00
J-Jamet
af0359132e Move comparators in SortNodeEnum 2018-03-25 15:29:50 +02:00
J-Jamet
85990879de Add serializable to binary to solve crash, refactor UUID and icon 2018-03-25 14:05:19 +02:00
J-Jamet
9436a4c3a5 Merge remote-tracking branch 'origin/develop' into develop 2018-03-24 20:06:45 +01:00
J-Jamet
efc786e318 Description for error API #49 2018-03-24 20:06:27 +01:00
J-Jamet
ed299b35e9 Change clones (To redefine) 2018-03-24 17:13:16 +01:00
J-Jamet
0defe9401f Solve password notification 2018-03-24 12:53:47 +01:00
J-Jamet
b66678f028 Refactor Groups and Entries methods 2018-03-24 00:02:08 +01:00
J-Jamet
b0cfd4292f Make attributes private in PwGroup and PwEntry 2018-03-23 21:30:50 +01:00
J-Jamet
8e390685cd Upgrade changelog and change extended visual 2018-03-23 19:14:58 +01:00
J-Jamet
9bcacdca4a Change extended visual 2018-03-23 19:04:19 +01:00
J-Jamet
c1969402f1 Add extended Ascii (ñæËÌÂÝÜ...) #36 2018-03-23 16:54:32 +01:00
J-Jamet
50bf22a4c7 Better fingerprint error management #38 #52 2018-03-23 13:48:51 +01:00
J-Jamet
cf93044d3f Start factorise 2018-03-22 23:06:05 +01:00
J-Jamet
33404add38 Verify nullity of group 2018-03-22 16:48:02 +01:00
J-Jamet
49ba74c38f Add Copy of password in settings 2018-03-22 15:48:46 +01:00
J-Jamet
3ed5db9819 Change search label in settings 2018-03-22 15:10:24 +01:00
J-Jamet
4535204d1e Move down file_browser settings 2018-03-22 15:03:44 +01:00
J-Jamet
18c656a555 Solve flickering and architecture for timeout #43 2018-03-22 14:36:23 +01:00
J-Jamet
42c28b5b95 Add timeout in launch 2018-03-22 13:04:45 +01:00
J-Jamet
9fc47fdf05 Solve timeout bug and remove compat class for invalidateOptionMenu 2018-03-21 23:17:40 +01:00
J-Jamet
9ef34599ce Solve bug of refresh entry 2018-03-21 22:25:35 +01:00
J-Jamet
bd3e5c6917 Solve color bugs 2018-03-21 22:14:57 +01:00
J-Jamet
7e9bed1e53 #55 Fix dispatch event 2018-03-21 21:59:55 +01:00
J-Jamet
ff2215929c Add menu_edit strings 2018-03-21 17:49:15 +01:00
J-Jamet
36d53e9788 Add file_browser strings 2018-03-21 17:32:35 +01:00
J-Jamet
6b9db7d40d Merge branch 'develop' of https://github.com/Kunzisoft/KeePassDX into develop 2018-03-21 17:02:00 +01:00
J-Jamet
30f805f5a9 #55 Fix listener to add node (dispatch event must to be refactored) 2018-03-21 16:13:40 +01:00
J-Jamet
64448ef218 #58 Horizontal scroll to see password and fix layout issues 2018-03-21 15:08:57 +01:00
J-Jamet
6e312e0420 #53 Fix password checkbox and add lambda 2018-03-21 14:36:42 +01:00
J-Jamet
1f7b86d34f #52 Add strike-through for 0 and check setting by default 2018-03-21 14:17:44 +01:00
J-Jamet
ae00fd5782 Allow notifications for all fields 2018-03-20 15:04:44 +01:00
J-Jamet
62f6f02467 Add notification to copy extra field, remove unused string 2018-03-20 14:47:49 +01:00
J-Jamet
55ee89314f Merge remote-tracking branch 'origin/develop' into develop 2018-03-20 13:43:28 +01:00
J-Jamet
b2f985aa03 New Notification engine 2018-03-20 13:43:11 +01:00
J-Jamet
b3a34c0138 Auto open select file #32 2018-03-19 18:17:29 +01:00
J-Jamet
1f06b09d38 Remove manual compat dependencies in settings 2018-03-19 16:49:26 +01:00
J-Jamet
758914a80a Solve bug of empty filename #51 2018-03-19 16:33:43 +01:00
J-Jamet
f2566abdcd Solve bug of icon information color 2018-03-19 16:20:38 +01:00
J-Jamet
cb6d479350 Default file as hint, change color 2018-03-19 16:09:33 +01:00
J-Jamet
846930a4f9 Refactor packages 2018-03-19 01:39:34 +01:00
J-Jamet
e788d89b18 Fix null in entry menu 2018-03-19 01:17:52 +01:00
J-Jamet
07f68cfe2f Add 30 minutes to timeout #43 2018-03-18 15:46:25 +01:00
J-Jamet
1c6ef51925 Launch notification only one time 2018-03-18 15:31:47 +01:00
J-Jamet
9995bc4d9f Fix App timeout for main cases #43 2018-03-18 15:31:22 +01:00
J-Jamet
accb931831 Upgrade clipboard and timeout 2018-03-18 13:26:13 +01:00
J-Jamet
42ac83c814 Upgrade version 2018-03-18 11:31:35 +01:00
J-Jamet
9ee9063c4d Refactor Timeout, delete useless Intents class 2018-03-17 20:18:06 +01:00
J-Jamet
8c38b361ea New notifications to copy fields 2018-03-17 20:01:13 +01:00
J-Jamet
cb919b2de5 Fix action "add group" for v3 #46 2018-03-17 11:07:33 +01:00
J-Jamet
679ea7c58f Fix Autofill settings crash #22 2018-03-16 19:15:39 +01:00
J-Jamet
21ebbd25f8 Update changelogs 2018-03-16 17:19:06 +01:00
J-Jamet
3c232ac5b6 Change HTTP to HTTPS 2018-03-16 16:36:23 +01:00
J-Jamet
d36d2408d7 Upgrade Notifications 2018-03-15 23:37:21 +01:00
J-Jamet
9fd59f850c Fix flickering and timeout toast in settings 2018-03-14 17:36:11 +01:00
J-Jamet
4cc7d1e74d Fix ActivityNotFound in FilePicker #37 2018-03-14 16:52:40 +01:00
J-Jamet
66f4353c3e Fix ActivityNotFound for AutoFill Service #37 2018-03-14 14:38:56 +01:00
J-Jamet
0acc83b066 Merge tag '2.5.0.0beta6' into develop
2.5.0.0beta6
2018-03-10 13:56:07 +01:00
433 changed files with 12301 additions and 14063 deletions

1
.gitignore vendored
View File

@@ -75,3 +75,4 @@ art/logo_512.png
# Dir linux # Dir linux
.directory .directory
*/.directory */.directory
.idea

22
.idea/compiler.xml generated
View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

6
.idea/encodings.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

20
.idea/gradle.xml generated
View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
<option name="gradleJvm" value="1.8" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -1,11 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintAppCompatResource" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintMissingTranslation" enabled="true" level="INFO" enabled_by_default="true" />
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
</inspection_tool>
</profile>
</component>

View File

@@ -1,7 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Project Default" />
<option name="USE_PROJECT_PROFILE" value="true" />
<version value="1.0" />
</settings>
</component>

49
.idea/misc.xml generated
View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.7</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

9
.idea/modules.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/KeePassDX.iml" filepath="$PROJECT_DIR$/KeePassDX.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -1,3 +1,25 @@
KeepassDX (2.5.0.0beta8)
* Hide custom entries protected
* Best management of field references (https://keepass.info/help/base/fieldrefs.html)
* Change database / default settings
* Add Autofill for search
* Add sorting by last access and by creation time
* Rebuild custom entries
* Refactor old code
* Fix bugs
KeepassDX (2.5.0.0beta7)
* Rebuild Notifications
* Change links to https
* Add extended Ascii (ñæËÌÂÝÜ...)
* Upgrade custom visibility font
* Best fingerprint error management
* Add setting to prevent the password copy
* Fix bugs
KeepassDX (2.5.0.0beta6)
* Fix crash
KeepassDX (2.5.0.0beta5) KeepassDX (2.5.0.0beta5)
* Autofill (Android O) * Autofill (Android O)
* Deletion for group * Deletion for group

View File

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

16
LICENSE
View File

@@ -1,7 +1,19 @@
--- ---
The KeePass icon was created by Jeremy JAMET and is licensed under the terms of GPLv3. KeePass DX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
The KeePass DX icon was created by Jeremy JAMET and is licensed under the terms of GPLv3.
--- ---
@@ -54,7 +66,7 @@ Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft <contact@kunzisoft.com>.
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
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@@ -54,7 +54,7 @@ Even if the application is free, to maintain the application, you can make donat
KeePass DX is free software: you can redistribute it and/or modify KeePass DX 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
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
KeePass DX is distributed in the hope that it will be useful, KeePass DX is distributed in the hope that it will be useful,

View File

@@ -2,17 +2,17 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion = 27 compileSdkVersion = 27
buildToolsVersion = "27.0.3" buildToolsVersion = '27.0.3'
defaultConfig { defaultConfig {
applicationId "com.kunzisoft.keepass" applicationId "com.kunzisoft.keepass"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 27 targetSdkVersion 27
versionCode = 6 versionCode = 8
versionName = "2.5.0.0beta6" versionName = "2.5.0.0beta8"
multiDexEnabled true multiDexEnabled true
testApplicationId = "com.keepassdroid.tests" testApplicationId = "com.kunzisoft.keepass.tests"
testInstrumentationRunner = "android.test.InstrumentationTestRunner" testInstrumentationRunner = "android.test.InstrumentationTestRunner"
ndk { ndk {
@@ -86,6 +86,10 @@ dependencies {
// if you don't use android.app.Fragment you can exclude support for them // if you don't use android.app.Fragment you can exclude support for them
exclude module: "support-v13" exclude module: "support-v13"
} }
// Apache Commons Collections
implementation group: 'commons-collections', name: 'commons-collections', version: '3.2.1'
// Base64
compile group: 'biz.source_code', name: 'base64coder', version: '2010-12-19'
annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionDispatcherVersion" annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionDispatcherVersion"
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.1' implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.1'
implementation group: 'com.google.guava', name: 'guava', version: '23.0-android' implementation group: 'com.google.guava', name: 'guava', version: '23.0-android'

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.tests;
import java.util.UUID;
import junit.framework.TestCase;
import com.keepassdroid.database.PwEntryV4;
import com.keepassdroid.database.PwGroupV4;
import com.keepassdroid.database.PwIconCustom;
import com.keepassdroid.database.PwIconStandard;
import com.keepassdroid.database.security.ProtectedBinary;
import com.keepassdroid.database.security.ProtectedString;
public class PwEntryTestV4 extends TestCase {
public void testAssign() {
PwEntryV4 entry = new PwEntryV4();
entry.additional = "test223";
entry.autoType = entry.new AutoType();
entry.autoType.defaultSequence = "1324";
entry.autoType.enabled = true;
entry.autoType.obfuscationOptions = 123412432109L;
entry.autoType.put("key", "value");
entry.backgroupColor = "blue";
entry.binaries.put("key1", new ProtectedBinary(false, new byte[] {0,1}));
entry.customIcon = new PwIconCustom(UUID.randomUUID(), new byte[0]);
entry.foregroundColor = "red";
entry.history.add(new PwEntryV4());
entry.icon = new PwIconStandard(5);
entry.overrideURL = "override";
entry.parent = new PwGroupV4();
entry.addField("key2", new ProtectedString(false, "value2"));
entry.url = "http://localhost";
entry.uuid = UUID.randomUUID();
PwEntryV4 target = new PwEntryV4();
target.assign(entry);
/* This test is not so useful now that I am not implementing value equality for Entries
assertTrue("Entries do not match.", entry.equals(target));
*/
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,11 +17,11 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.tests.database.TestData; import com.kunzisoft.keepass.tests.database.TestData;
public class AccentTest extends AndroidTestCase { public class AccentTest extends AndroidTestCase {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
@@ -29,7 +29,7 @@ public class OutputTests extends TestSuite {
public static Test suite() { public static Test suite() {
return new TestSuiteBuilder(AllTests.class) return new TestSuiteBuilder(AllTests.class)
.includePackages("com.keepassdroid.tests.output") .includePackages("com.kunzisoft.keepass.tests.output")
.build(); .build();
} }
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,11 +17,11 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.database.PwDate; import com.kunzisoft.keepass.database.PwDate;
public class PwDateTest extends TestCase { public class PwDateTest extends TestCase {
public void testDate() { public void testDate() {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -27,8 +27,8 @@ import java.util.Calendar;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.PwEntryV3; import com.kunzisoft.keepass.database.PwEntryV3;
import com.keepassdroid.tests.database.TestData; import com.kunzisoft.keepass.tests.database.TestData;
public class PwEntryTestV3 extends AndroidTestCase { public class PwEntryTestV3 extends AndroidTestCase {
PwEntryV3 mPE; PwEntryV3 mPE;
@@ -37,12 +37,12 @@ public class PwEntryTestV3 extends AndroidTestCase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
mPE = (PwEntryV3) TestData.GetTest1(getContext()).entries.get(0); mPE = (PwEntryV3) TestData.GetTest1(getContext()).getEntryAt(0);
} }
public void testName() { public void testName() {
assertTrue("Name was " + mPE.title, mPE.title.equals("Amazon")); assertTrue("Name was " + mPE.getTitle(), mPE.getTitle().equals("Amazon"));
} }
public void testPassword() throws UnsupportedEncodingException { public void testPassword() throws UnsupportedEncodingException {
@@ -54,7 +54,7 @@ public class PwEntryTestV3 extends AndroidTestCase {
public void testCreation() { public void testCreation() {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.setTime(mPE.tCreation.getJDate()); cal.setTime(mPE.getCreationTime().getDate());
assertEquals("Incorrect year.", cal.get(Calendar.YEAR), 2009); assertEquals("Incorrect year.", cal.get(Calendar.YEAR), 2009);
assertEquals("Incorrect month.", cal.get(Calendar.MONTH), 3); assertEquals("Incorrect month.", cal.get(Calendar.MONTH), 3);

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests;
import com.kunzisoft.keepass.database.AutoType;
import com.kunzisoft.keepass.database.PwEntryV4;
import com.kunzisoft.keepass.database.PwGroupV4;
import com.kunzisoft.keepass.database.PwIconCustom;
import com.kunzisoft.keepass.database.PwIconStandard;
import com.kunzisoft.keepass.database.security.ProtectedBinary;
import com.kunzisoft.keepass.database.security.ProtectedString;
import junit.framework.TestCase;
import java.util.UUID;
public class PwEntryTestV4 extends TestCase {
public void testAssign() {
PwEntryV4 entry = new PwEntryV4();
entry.setAdditional("test223");
entry.setAutoType(new AutoType());
entry.getAutoType().defaultSequence = "1324";
entry.getAutoType().enabled = true;
entry.getAutoType().obfuscationOptions = 123412432109L;
entry.getAutoType().put("key", "value");
entry.setBackgroupColor("blue");
entry.putProtectedBinary("key1", new ProtectedBinary(false, new byte[] {0,1}));
entry.setCustomIcon(new PwIconCustom(UUID.randomUUID(), new byte[0]));
entry.setForegroundColor("red");
entry.addToHistory(new PwEntryV4());
entry.setIcon(new PwIconStandard(5));
entry.setOverrideURL("override");
entry.setParent(new PwGroupV4());
entry.addExtraField("key2", new ProtectedString(false, "value2"));
entry.setUrl("http://localhost");
entry.setUUID(UUID.randomUUID());
PwEntryV4 target = new PwEntryV4();
target.updateWith(entry);
/* This test is not so useful now that I am not implementing value equality for Entries
assertTrue("Entries do not match.", entry.equals(target));
*/
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,13 +17,13 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.PwGroupV3; import com.kunzisoft.keepass.database.PwGroupV3;
import com.keepassdroid.tests.database.TestData; import com.kunzisoft.keepass.tests.database.TestData;
public class PwGroupTest extends AndroidTestCase { public class PwGroupTest extends AndroidTestCase {
@@ -38,7 +38,7 @@ public class PwGroupTest extends AndroidTestCase {
} }
public void testGroupName() { public void testGroupName() {
assertTrue("Name was " + mPG.name, mPG.name.equals("Internet")); assertTrue("Name was " + mPG.getName(), mPG.getName().equals("Internet"));
} }
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -29,8 +29,8 @@ import android.content.res.AssetManager;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import com.keepassdroid.utils.EmptyUtils; import com.kunzisoft.keepass.utils.EmptyUtils;
import com.keepassdroid.utils.UriUtil; import com.kunzisoft.keepass.utils.UriUtil;
public class TestUtil { public class TestUtil {
private static final File sdcard = Environment.getExternalStorageDirectory(); private static final File sdcard = Environment.getExternalStorageDirectory();

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests; package com.kunzisoft.keepass.tests;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -28,10 +28,10 @@ import java.util.UUID;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.database.PwDate; import com.kunzisoft.keepass.database.PwDate;
import com.keepassdroid.stream.LEDataInputStream; import com.kunzisoft.keepass.stream.LEDataInputStream;
import com.keepassdroid.stream.LEDataOutputStream; import com.kunzisoft.keepass.stream.LEDataOutputStream;
import com.keepassdroid.utils.Types; import com.kunzisoft.keepass.utils.Types;
public class TypesTest extends TestCase { public class TypesTest extends TestCase {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,9 +17,11 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.crypto; package com.kunzisoft.keepass.tests.crypto;
import static org.junit.Assert.assertArrayEquals; import com.kunzisoft.keepass.crypto.CipherFactory;
import junit.framework.TestCase;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@@ -33,9 +35,7 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase; import static org.junit.Assert.assertArrayEquals;
import com.keepassdroid.crypto.CipherFactory;
public class AESTest extends TestCase { public class AESTest extends TestCase {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.crypto; package com.kunzisoft.keepass.tests.crypto;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -37,11 +37,11 @@ import javax.crypto.NoSuchPaddingException;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.crypto.CipherFactory; import com.kunzisoft.keepass.crypto.CipherFactory;
import com.keepassdroid.crypto.engine.AesEngine; import com.kunzisoft.keepass.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine; import com.kunzisoft.keepass.crypto.engine.CipherEngine;
import com.keepassdroid.stream.BetterCipherInputStream; import com.kunzisoft.keepass.stream.BetterCipherInputStream;
import com.keepassdroid.stream.LEDataInputStream; import com.kunzisoft.keepass.stream.LEDataInputStream;
public class CipherTest extends TestCase { public class CipherTest extends TestCase {
private Random rand = new Random(); private Random rand = new Random();

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.crypto; package com.kunzisoft.keepass.tests.crypto;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -26,8 +26,8 @@ import java.util.Random;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.crypto.finalkey.AndroidFinalKey; import com.kunzisoft.keepass.crypto.finalkey.AndroidFinalKey;
import com.keepassdroid.crypto.finalkey.NativeFinalKey; import com.kunzisoft.keepass.crypto.finalkey.NativeFinalKey;
public class FinalKeyTest extends TestCase { public class FinalKeyTest extends TestCase {
private Random mRand; private Random mRand;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,20 +17,21 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.util.List; import java.util.List;
import android.content.Context; import android.content.Context;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.Database; import com.kunzisoft.keepass.database.Database;
import com.keepassdroid.database.PwDatabase; import com.kunzisoft.keepass.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3; import com.kunzisoft.keepass.database.PwDatabaseV3;
import com.keepassdroid.database.PwEntry; import com.kunzisoft.keepass.database.PwEntry;
import com.keepassdroid.database.PwGroup; import com.kunzisoft.keepass.database.PwEntryV3;
import com.keepassdroid.database.edit.DeleteGroup; import com.kunzisoft.keepass.database.PwGroup;
import com.keepassdroid.search.SearchDbHelper; import com.kunzisoft.keepass.database.edit.DeleteGroup;
import com.kunzisoft.keepass.search.SearchDbHelper;
public class DeleteEntry extends AndroidTestCase { public class DeleteEntry extends AndroidTestCase {
private static final String GROUP1_NAME = "Group1"; private static final String GROUP1_NAME = "Group1";
@@ -54,7 +55,7 @@ public class DeleteEntry extends AndroidTestCase {
return; return;
} }
PwDatabaseV3 pm = (PwDatabaseV3) db.pm; PwDatabaseV3 pm = (PwDatabaseV3) db.getPwDatabase();
PwGroup group1 = getGroup(pm, GROUP1_NAME); PwGroup group1 = getGroup(pm, GROUP1_NAME);
assertNotNull("Could not find group1", group1); assertNotNull("Could not find group1", group1);
@@ -71,8 +72,8 @@ public class DeleteEntry extends AndroidTestCase {
// Verify the entries were removed from the search index // Verify the entries were removed from the search index
SearchDbHelper dbHelp = new SearchDbHelper(ctx); SearchDbHelper dbHelp = new SearchDbHelper(ctx);
PwGroup results1 = dbHelp.search(db, ENTRY1_NAME); PwGroup results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME);
PwGroup results2 = dbHelp.search(db, ENTRY2_NAME); PwGroup results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME);
assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries()); assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries());
assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries()); assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries());
@@ -80,15 +81,13 @@ public class DeleteEntry extends AndroidTestCase {
// Verify the group was deleted // Verify the group was deleted
group1 = getGroup(pm, GROUP1_NAME); group1 = getGroup(pm, GROUP1_NAME);
assertNull("Group 1 was not removed.", group1); assertNull("Group 1 was not removed.", group1);
} }
private PwEntry getEntry(PwDatabaseV3 pm, String name) { private PwEntryV3 getEntry(PwDatabaseV3 pm, String name) {
List<PwEntry> entries = pm.entries; List<PwEntryV3> entries = pm.getEntries();
for ( int i = 0; i < entries.size(); i++ ) { for ( int i = 0; i < entries.size(); i++ ) {
PwEntry entry = entries.get(i); PwEntryV3 entry = entries.get(i);
if ( entry.getTitle().equals(name) ) { if ( entry.getTitle().equals(name) ) {
return entry; return entry;
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,34 +17,36 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.database.PwDatabaseV4; import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.keepassdroid.database.PwEntryV4; import com.kunzisoft.keepass.database.PwEntryV4;
public class EntryV4 extends TestCase { public class EntryV4 extends TestCase {
public void testBackup() { public void testBackup() {
PwDatabaseV4 db = new PwDatabaseV4(); PwDatabaseV4 db = new PwDatabaseV4();
db.historyMaxItems = 2; db.setHistoryMaxItems(2);
PwEntryV4 entry = new PwEntryV4(); PwEntryV4 entry = new PwEntryV4();
entry.setTitle("Title1", db); entry.startToManageFieldReferences(db);
entry.setUsername("User1", db); entry.setTitle("Title1");
entry.setUsername("User1");
entry.createBackup(db); entry.createBackup(db);
entry.setTitle("Title2", db); entry.setTitle("Title2");
entry.setUsername("User2", db); entry.setUsername("User2");
entry.createBackup(db); entry.createBackup(db);
entry.setTitle("Title3", db); entry.setTitle("Title3");
entry.setUsername("User3", db); entry.setUsername("User3");
entry.createBackup(db); entry.createBackup(db);
PwEntryV4 backup = entry.history.get(0); PwEntryV4 backup = entry.getHistory().get(0);
entry.endToManageFieldReferences();
assertEquals("Title2", backup.getTitle()); assertEquals("Title2", backup.getTitle());
assertEquals("User2", backup.getUsername()); assertEquals("User2", backup.getUsername());
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
@@ -25,9 +25,9 @@ import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.load.ImporterV3; import com.kunzisoft.keepass.database.load.ImporterV3;
import com.keepassdroid.tests.TestUtil; import com.kunzisoft.keepass.tests.TestUtil;
import com.keepassdroid.utils.UriUtil; import com.kunzisoft.keepass.utils.UriUtil;
import java.io.InputStream; import java.io.InputStream;
import java.io.File; import java.io.File;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.io.InputStream; import java.io.InputStream;
@@ -25,9 +25,9 @@ import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.PwDatabaseV3; import com.kunzisoft.keepass.database.PwDatabaseV3;
import com.keepassdroid.database.PwEncryptionAlgorithm; import com.kunzisoft.keepass.database.PwEncryptionAlgorithm;
import com.keepassdroid.database.load.ImporterV3; import com.kunzisoft.keepass.database.load.ImporterV3;
public class Kdb3Twofish extends AndroidTestCase { public class Kdb3Twofish extends AndroidTestCase {
public void testReadTwofish() throws Exception { public void testReadTwofish() throws Exception {
@@ -40,10 +40,9 @@ public class Kdb3Twofish extends AndroidTestCase {
PwDatabaseV3 db = importer.openDatabase(is, "12345", null); PwDatabaseV3 db = importer.openDatabase(is, "12345", null);
assertTrue(db.algorithm == PwEncryptionAlgorithm.Twofish); assertTrue(db.getEncryptionAlgorithm() == PwEncryptionAlgorithm.Twofish);
is.close(); is.close();
} }
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -29,16 +29,16 @@ import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.PwDatabaseV4; import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.keepassdroid.database.exception.InvalidDBException; import com.kunzisoft.keepass.database.exception.InvalidDBException;
import com.keepassdroid.database.exception.PwDbOutputException; import com.kunzisoft.keepass.database.exception.PwDbOutputException;
import com.keepassdroid.database.load.Importer; import com.kunzisoft.keepass.database.load.Importer;
import com.keepassdroid.database.load.ImporterFactory; import com.kunzisoft.keepass.database.load.ImporterFactory;
import com.keepassdroid.database.load.ImporterV4; import com.kunzisoft.keepass.database.load.ImporterV4;
import com.keepassdroid.database.save.PwDbOutput; import com.kunzisoft.keepass.database.save.PwDbOutput;
import com.keepassdroid.database.save.PwDbV4Output; import com.kunzisoft.keepass.database.save.PwDbV4Output;
import com.keepassdroid.stream.CopyInputStream; import com.kunzisoft.keepass.stream.CopyInputStream;
import com.keepassdroid.tests.TestUtil; import com.kunzisoft.keepass.tests.TestUtil;
public class Kdb4 extends AndroidTestCase { public class Kdb4 extends AndroidTestCase {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,18 +17,17 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.io.InputStream;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.crypto.CipherFactory; import com.kunzisoft.keepass.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.AesEngine; import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.keepassdroid.database.PwDatabaseV4; import com.kunzisoft.keepass.database.load.ImporterV4;
import com.keepassdroid.database.load.ImporterV4;
import java.io.InputStream;
public class Kdb4Header extends AndroidTestCase { public class Kdb4Header extends AndroidTestCase {
public void testReadHeader() throws Exception { public void testReadHeader() throws Exception {
@@ -41,9 +40,9 @@ public class Kdb4Header extends AndroidTestCase {
PwDatabaseV4 db = importer.openDatabase(is, "12345", null); PwDatabaseV4 db = importer.openDatabase(is, "12345", null);
assertEquals(6000, db.numKeyEncRounds); assertEquals(6000, db.getNumberKeyEncryptionRounds());
assertTrue(db.dataCipher.equals(AesEngine.CIPHER_UUID)); assertTrue(db.getDataCipher().equals(AesEngine.CIPHER_UUID));
is.close(); is.close();

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.io.InputStream; import java.io.InputStream;
import java.util.UUID; import java.util.UUID;
@@ -27,15 +27,16 @@ import android.content.res.AssetManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import biz.source_code.base64Coder.Base64Coder; import biz.source_code.base64Coder.Base64Coder;
import com.keepassdroid.database.PwDatabaseV4; import com.kunzisoft.keepass.database.PwDatabase;
import com.keepassdroid.database.PwEntryV4; import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.keepassdroid.database.load.ImporterV4; import com.kunzisoft.keepass.database.PwEntryV4;
import com.keepassdroid.utils.SprEngine; import com.kunzisoft.keepass.database.load.ImporterV4;
import com.keepassdroid.utils.Types; import com.kunzisoft.keepass.utils.SprEngineV4;
import com.kunzisoft.keepass.utils.Types;
public class SprEngineTest extends AndroidTestCase { public class SprEngineTest extends AndroidTestCase {
private PwDatabaseV4 db; private PwDatabaseV4 db;
private SprEngine spr; private SprEngineV4 spr;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
@@ -51,7 +52,7 @@ public class SprEngineTest extends AndroidTestCase {
is.close(); is.close();
spr = SprEngine.getInstance(db); spr = new SprEngineV4();
} }
private final String REF = "{REF:P@I:2B1D56590D961F48A8CE8C392CE6CD35}"; private final String REF = "{REF:P@I:2B1D56590D961F48A8CE8C392CE6CD35}";
@@ -60,7 +61,7 @@ public class SprEngineTest extends AndroidTestCase {
public void testRefReplace() { public void testRefReplace() {
UUID entryUUID = decodeUUID(ENCODE_UUID); UUID entryUUID = decodeUUID(ENCODE_UUID);
PwEntryV4 entry = (PwEntryV4) db.entries.get(entryUUID); PwEntryV4 entry = (PwEntryV4) db.getEntryByUUIDId(entryUUID);
assertEquals(RESULT, spr.compile(REF, entry, db)); assertEquals(RESULT, spr.compile(REF, entry, db));
@@ -69,7 +70,7 @@ public class SprEngineTest extends AndroidTestCase {
private UUID decodeUUID(String encoded) { private UUID decodeUUID(String encoded) {
if (encoded == null || encoded.length() == 0 ) { if (encoded == null || encoded.length() == 0 ) {
return PwDatabaseV4.UUID_ZERO; return PwDatabase.UUID_ZERO;
} }
byte[] buf = Base64Coder.decode(encoded); byte[] buf = Base64Coder.decode(encoded);

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.database; package com.kunzisoft.keepass.tests.database;
import java.io.InputStream; import java.io.InputStream;
@@ -25,10 +25,10 @@ import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.net.Uri; import android.net.Uri;
import com.keepassdroid.database.Database; import com.kunzisoft.keepass.database.Database;
import com.keepassdroid.database.PwDatabaseV3Debug; import com.kunzisoft.keepass.database.PwDatabaseV3Debug;
import com.keepassdroid.database.load.Importer; import com.kunzisoft.keepass.database.load.Importer;
import com.keepassdroid.tests.TestUtil; import com.kunzisoft.keepass.tests.TestUtil;
public class TestData { public class TestData {
private static final String TEST1_KEYFILE = ""; private static final String TEST1_KEYFILE = "";
@@ -58,10 +58,10 @@ public class TestData {
InputStream keyIs = TestUtil.getKeyFileInputStream(ctx, keyfile); InputStream keyIs = TestUtil.getKeyFileInputStream(ctx, keyfile);
Db.LoadData(ctx, is, password, keyIs, Importer.DEBUG); Db.loadData(ctx, is, password, keyIs, Importer.DEBUG);
Uri.Builder b = new Uri.Builder(); Uri.Builder b = new Uri.Builder();
Db.mUri = b.scheme("file").path(filename).build(); Db.setUri(b.scheme("file").path(filename).build());
return Db; return Db;
@@ -72,6 +72,6 @@ public class TestData {
GetDb1(ctx); GetDb1(ctx);
} }
return (PwDatabaseV3Debug) mDb1.pm; return (PwDatabaseV3Debug) mDb1.getPwDatabase();
} }
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.output; package com.kunzisoft.keepass.tests.output;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -32,16 +32,16 @@ import java.security.NoSuchAlgorithmException;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.keepassdroid.database.PwDatabaseV3Debug; import com.kunzisoft.keepass.database.PwDatabaseV3Debug;
import com.keepassdroid.database.PwDbHeader; import com.kunzisoft.keepass.database.PwDbHeader;
import com.keepassdroid.database.PwDbHeaderV3; import com.kunzisoft.keepass.database.PwDbHeaderV3;
import com.keepassdroid.database.exception.PwDbOutputException; import com.kunzisoft.keepass.database.exception.PwDbOutputException;
import com.keepassdroid.database.save.PwDbHeaderOutputV3; import com.kunzisoft.keepass.database.save.PwDbHeaderOutputV3;
import com.keepassdroid.database.save.PwDbV3Output; import com.kunzisoft.keepass.database.save.PwDbV3Output;
import com.keepassdroid.database.save.PwDbV3OutputDebug; import com.kunzisoft.keepass.database.save.PwDbV3OutputDebug;
import com.keepassdroid.stream.NullOutputStream; import com.kunzisoft.keepass.stream.NullOutputStream;
import com.keepassdroid.tests.TestUtil; import com.kunzisoft.keepass.tests.TestUtil;
import com.keepassdroid.tests.database.TestData; import com.kunzisoft.keepass.tests.database.TestData;
public class PwManagerOutputTest extends AndroidTestCase { public class PwManagerOutputTest extends AndroidTestCase {
PwDatabaseV3Debug mPM; PwDatabaseV3Debug mPM;
@@ -60,7 +60,7 @@ public class PwManagerOutputTest extends AndroidTestCase {
pos.outputPlanGroupAndEntries(bos); pos.outputPlanGroupAndEntries(bos);
assertTrue("No output", bos.toByteArray().length > 0); assertTrue("No output", bos.toByteArray().length > 0);
assertArrayEquals("Group and entry output doesn't match.", mPM.postHeader, bos.toByteArray()); assertArrayEquals("Group and entry output doesn't match.", mPM.getPostHeader(), bos.toByteArray());
} }
@@ -77,7 +77,7 @@ public class PwManagerOutputTest extends AndroidTestCase {
byte[] digest = md.digest(); byte[] digest = md.digest();
assertTrue("No output", digest.length > 0); assertTrue("No output", digest.length > 0);
assertArrayEquals("Hash of groups and entries failed.", mPM.dbHeader.contentsHash, digest); assertArrayEquals("Hash of groups and entries failed.", mPM.getDbHeader().contentsHash, digest);
} }
private void assertHeadersEquals(PwDbHeaderV3 expected, PwDbHeaderV3 actual) { private void assertHeadersEquals(PwDbHeaderV3 expected, PwDbHeaderV3 actual) {
@@ -100,10 +100,10 @@ public class PwManagerOutputTest extends AndroidTestCase {
PwDbHeaderV3 header = pActual.outputHeader(bActual); PwDbHeaderV3 header = pActual.outputHeader(bActual);
ByteArrayOutputStream bExpected = new ByteArrayOutputStream(); ByteArrayOutputStream bExpected = new ByteArrayOutputStream();
PwDbHeaderOutputV3 outExpected = new PwDbHeaderOutputV3(mPM.dbHeader, bExpected); PwDbHeaderOutputV3 outExpected = new PwDbHeaderOutputV3(mPM.getDbHeader(), bExpected);
outExpected.output(); outExpected.output();
assertHeadersEquals(mPM.dbHeader, header); assertHeadersEquals(mPM.getDbHeader(), header);
assertTrue("No output", bActual.toByteArray().length > 0); assertTrue("No output", bActual.toByteArray().length > 0);
assertArrayEquals("Header does not match.", bExpected.toByteArray(), bActual.toByteArray()); assertArrayEquals("Header does not match.", bExpected.toByteArray(), bActual.toByteArray());
} }
@@ -114,7 +114,7 @@ public class PwManagerOutputTest extends AndroidTestCase {
PwDbHeader hActual = pActual.outputHeader(bActual); PwDbHeader hActual = pActual.outputHeader(bActual);
byte[] finalKey = pActual.getFinalKey(hActual); byte[] finalKey = pActual.getFinalKey(hActual);
assertArrayEquals("Keys mismatched", mPM.finalKey, finalKey); assertArrayEquals("Keys mismatched", mPM.getFinalKey(), finalKey);
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.search; package com.kunzisoft.keepass.tests.search;
import android.content.Context; import android.content.Context;
@@ -25,10 +25,9 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.database.Database;
import com.keepassdroid.database.Database; import com.kunzisoft.keepass.database.PwGroup;
import com.keepassdroid.database.PwGroup; import com.kunzisoft.keepass.tests.database.TestData;
import com.keepassdroid.tests.database.TestData;
public class SearchTest extends AndroidTestCase { public class SearchTest extends AndroidTestCase {
@@ -42,21 +41,21 @@ public class SearchTest extends AndroidTestCase {
} }
public void testSearch() { public void testSearch() {
PwGroup results = mDb.Search("Amazon"); PwGroup results = mDb.search("Amazon");
assertTrue("Search result not found.", results.numbersOfChildEntries() > 0); assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
} }
public void testBackupIncluded() { public void testBackupIncluded() {
updateOmitSetting(false); updateOmitSetting(false);
PwGroup results = mDb.Search("BackupOnly"); PwGroup results = mDb.search("BackupOnly");
assertTrue("Search result not found.", results.numbersOfChildEntries() > 0); assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
} }
public void testBackupExcluded() { public void testBackupExcluded() {
updateOmitSetting(true); updateOmitSetting(true);
PwGroup results = mDb.Search("BackupOnly"); PwGroup results = mDb.search("BackupOnly");
assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0); assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0);
} }
@@ -66,7 +65,7 @@ public class SearchTest extends AndroidTestCase {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(ctx.getString(R.string.settings_omitbackup_key), setting); editor.putBoolean("settings_omitbackup_key", setting);
editor.commit(); editor.commit();
} }

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.stream; package com.kunzisoft.keepass.tests.stream;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@@ -30,8 +30,8 @@ import java.util.zip.GZIPOutputStream;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.keepassdroid.stream.HashedBlockInputStream; import com.kunzisoft.keepass.stream.HashedBlockInputStream;
import com.keepassdroid.stream.HashedBlockOutputStream; import com.kunzisoft.keepass.stream.HashedBlockOutputStream;
public class HashedBlock extends TestCase { public class HashedBlock extends TestCase {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,11 +17,11 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.tests.utils; package com.kunzisoft.keepass.tests.utils;
import java.util.Locale; import java.util.Locale;
import com.keepassdroid.utils.StrUtil; import com.kunzisoft.keepass.utils.StrUtil;
import junit.framework.TestCase; import junit.framework.TestCase;

View File

@@ -16,10 +16,10 @@
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:name="com.keepassdroid.app.App" android:name="com.kunzisoft.keepass.app.App"
android:allowBackup="true" android:allowBackup="true"
android:fullBackupContent="@xml/backup" android:fullBackupContent="@xml/backup"
android:backupAgent="com.keepassdroid.backup.SettingsBackupAgent" android:backupAgent="com.kunzisoft.keepass.backup.SettingsBackupAgent"
android:theme="@style/KeepassDXStyle.Light" android:theme="@style/KeepassDXStyle.Light"
tools:replace="android:theme"> tools:replace="android:theme">
<!-- TODO backup API Key --> <!-- TODO backup API Key -->
@@ -38,7 +38,7 @@
android:resource="@xml/nnf_provider_paths" /> android:resource="@xml/nnf_provider_paths" />
</provider> </provider>
<activity <activity
android:name="com.keepassdroid.fileselect.FilePickerStylishActivity" android:name="com.kunzisoft.keepass.fileselect.FilePickerStylishActivity"
android:label="@string/app_name"> android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.GET_CONTENT" /> <action android:name="android.intent.action.GET_CONTENT" />
@@ -54,16 +54,16 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name="com.keepassdroid.fileselect.FileSelectActivity" android:name="com.kunzisoft.keepass.fileselect.FileSelectActivity"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="stateHidden" /> android:windowSoftInputMode="stateHidden" />
<activity <activity
android:name="com.keepassdroid.activities.AboutActivity" android:name="com.kunzisoft.keepass.activities.AboutActivity"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:label="@string/menu_about" /> android:label="@string/menu_about" />
<activity <activity
android:name="com.keepassdroid.password.PasswordActivity" android:name="com.kunzisoft.keepass.password.PasswordActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
@@ -103,24 +103,24 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name="com.keepassdroid.activities.GroupActivity" android:name="com.kunzisoft.keepass.activities.GroupActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustPan"> android:windowSoftInputMode="adjustPan">
<meta-data <meta-data
android:name="android.app.default_searchable" android:name="android.app.default_searchable"
android:value="com.keepassdroid.search.SearchResults" android:value="com.kunzisoft.keepass.search.SearchResults"
android:exported="false"/> android:exported="false"/>
</activity> </activity>
<activity <activity
android:name="com.keepassdroid.activities.EntryActivity" android:name="com.kunzisoft.keepass.activities.EntryActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="stateHidden" /> android:windowSoftInputMode="stateHidden" />
<activity <activity
android:name="com.keepassdroid.activities.EntryEditActivity" android:name="com.kunzisoft.keepass.activities.EntryEditActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="stateHidden" /> android:windowSoftInputMode="stateHidden" />
<activity <activity
android:name="com.keepassdroid.search.SearchResultsActivity" android:name="com.kunzisoft.keepass.search.SearchResultsActivity"
android:launchMode="standard"> android:launchMode="standard">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH" />
@@ -130,13 +130,18 @@
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable" /> android:resource="@xml/searchable" />
</activity> </activity>
<activity android:name="com.keepassdroid.settings.SettingsActivity" /> <activity android:name="com.kunzisoft.keepass.settings.SettingsActivity" />
<activity android:name="com.keepassdroid.autofill.AutoFillAuthActivity" <activity android:name="com.kunzisoft.keepass.autofill.AutoFillAuthActivity"
android:configChanges="orientation|keyboardHidden" /> android:configChanges="orientation|keyboardHidden" />
<activity android:name="com.kunzisoft.keepass.settings.SettingsAutofillActivity" />
<service android:name="com.keepassdroid.services.TimeoutService" /> <service android:name="com.kunzisoft.keepass.timeout.TimeoutService" />
<service <service
android:name="com.keepassdroid.autofill.KeeAutofillService" android:name="com.kunzisoft.keepass.notifications.NotificationCopyingService"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.autofill.KeeAutofillService"
android:label="@string/autofill_service_name" android:label="@string/autofill_service_name"
android:permission="android.permission.BIND_AUTOFILL_SERVICE"> android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<meta-data <meta-data

View File

@@ -1,225 +0,0 @@
// Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
// www.source-code.biz, www.inventec.ch/chdh
//
// This module is multi-licensed and may be used under the terms
// of any of the following licenses:
//
// EPL, Eclipse Public License, http://www.eclipse.org/legal
// LGPL, GNU Lesser General Public License, http://www.gnu.org/licenses/lgpl.html
// AL, Apache License, http://www.apache.org/licenses
// BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.
package biz.source_code.base64Coder;
/**
* A Base64 encoder/decoder.
*
* <p>
* This class is used to encode and decode data in Base64 format as described in RFC 1521.
*
* <p>
* Project home page: <a href="http://www.source-code.biz/base64coder/java/">www.source-code.biz/base64coder/java</a><br>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / AL / BSD.
*/
public class Base64Coder {
// The line separator string of the operating system.
private static final String systemLineSeparator = System.getProperty("line.separator");
// Mapping table from 6-bit nibbles to Base64 characters.
private static char[] map1 = new char[64];
static {
int i=0;
for (char c='A'; c<='Z'; c++) map1[i++] = c;
for (char c='a'; c<='z'; c++) map1[i++] = c;
for (char c='0'; c<='9'; c++) map1[i++] = c;
map1[i++] = '+'; map1[i++] = '/'; }
// Mapping table from Base64 characters to 6-bit nibbles.
private static byte[] map2 = new byte[128];
static {
for (int i=0; i<map2.length; i++) map2[i] = -1;
for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; }
/**
* Encodes a string into Base64 format.
* No blanks or line breaks are inserted.
* @param s A String to be encoded.
* @return A String containing the Base64 encoded data.
*/
public static String encodeString (String s) {
return new String(encode(s.getBytes())); }
/**
* Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters.
* This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.
* @param in An array containing the data bytes to be encoded.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines (byte[] in) {
return encodeLines(in, 0, in.length, 76, systemLineSeparator); }
/**
* Encodes a byte array into Base 64 format and breaks the output into lines.
* @param in An array containing the data bytes to be encoded.
* @param iOff Offset of the first byte in <code>in</code> to be processed.
* @param iLen Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>.
* @param lineLen Line length for the output data. Should be a multiple of 4.
* @param lineSeparator The line separator to be used to separate the output lines.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator) {
int blockLen = (lineLen*3) / 4;
if (blockLen <= 0) throw new IllegalArgumentException();
int lines = (iLen+blockLen-1) / blockLen;
int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length();
StringBuilder buf = new StringBuilder(bufLen);
int ip = 0;
while (ip < iLen) {
int l = Math.min(iLen-ip, blockLen);
buf.append (encode(in, iOff+ip, l));
buf.append (lineSeparator);
ip += l; }
return buf.toString(); }
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in) {
return encode(in, 0, in.length); }
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @param iLen Number of bytes to process in <code>in</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in, int iLen) {
return encode(in, 0, iLen); }
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @param iOff Offset of the first byte in <code>in</code> to be processed.
* @param iLen Number of bytes to process in <code>in</code>, starting at <code>iOff</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in, int iOff, int iLen) {
int oDataLen = (iLen*4+2)/3; // output length without padding
int oLen = ((iLen+2)/3)*4; // output length including padding
char[] out = new char[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd) {
int i0 = in[ip++] & 0xff;
int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
int o0 = i0 >>> 2;
int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
int o3 = i2 & 0x3F;
out[op++] = map1[o0];
out[op++] = map1[o1];
out[op] = op < oDataLen ? map1[o2] : '='; op++;
out[op] = op < oDataLen ? map1[o3] : '='; op++; }
return out; }
/**
* Decodes a string from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param s A Base64 String to be decoded.
* @return A String containing the decoded data.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static String decodeString (String s) {
return new String(decode(s)); }
/**
* Decodes a byte array from Base64 format and ignores line separators, tabs and blanks.
* CR, LF, Tab and Space characters are ignored in the input data.
* This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
* @param s A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decodeLines (String s) {
char[] buf = new char[s.length()];
int p = 0;
for (int ip = 0; ip < s.length(); ip++) {
char c = s.charAt(ip);
if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
buf[p++] = c; }
return decode(buf, 0, p); }
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param s A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (String s) {
return decode(s.toCharArray()); }
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param in A character array containing the Base64 encoded data.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (char[] in) {
return decode(in, 0, in.length); }
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param in A character array containing the Base64 encoded data.
* @param iOff Offset of the first character in <code>in</code> to be processed.
* @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (char[] in, int iOff, int iLen) {
if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--;
int oLen = (iLen*3) / 4;
byte[] out = new byte[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd) {
int i0 = in[ip++];
int i1 = in[ip++];
int i2 = ip < iEnd ? in[ip++] : 'A';
int i3 = ip < iEnd ? in[ip++] : 'A';
if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
int b0 = map2[i0];
int b1 = map2[i1];
int b2 = map2[i2];
int b3 = map2[i3];
if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
int o0 = ( b0 <<2) | (b1>>>4);
int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
int o2 = ((b2 & 3)<<6) | b3;
out[op++] = (byte)o0;
if (op<oLen) out[op++] = (byte)o1;
if (op<oLen) out[op++] = (byte)o2; }
return out; }
// Dummy constructor.
private Base64Coder() {}
} // end class Base64Coder

View File

@@ -1,487 +0,0 @@
/*
*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ActivityCompat;
import com.keepassdroid.database.Database;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.exception.SamsungClipboardException;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.settings.PreferencesUtil;
import com.keepassdroid.password.PasswordActivity;
import com.keepassdroid.tasks.UIToastTask;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.Types;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.EntryContentsView;
import com.kunzisoft.keepass.R;
import java.util.Date;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import static com.keepassdroid.settings.PreferencesUtil.isClipboardNotificationsEnable;
public class EntryActivity extends LockingHideActivity {
public static final String KEY_ENTRY = "entry";
public static final int NOTIFY_USERNAME = 1;
public static final int NOTIFY_PASSWORD = 2;
private ImageView titleIconView;
private TextView titleView;
private EntryContentsView entryContentsView;
protected PwEntry mEntry;
private Timer mTimer = new Timer();
private boolean mShowPassword;
private NotificationManager mNM;
private BroadcastReceiver mIntentReceiver;
protected boolean readOnly = false;
public static void launch(Activity act, PwEntry pw) {
Intent intent = new Intent(act, EntryActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Database db = App.getDB();
// Likely the app has been killed exit the activity
if ( ! db.Loaded() ) {
finish();
return;
}
readOnly = db.readOnly;
mShowPassword = !PreferencesUtil.isPasswordMask(this);
// Get Entry from UUID
Intent i = getIntent();
UUID uuid = Types.bytestoUUID(i.getByteArrayExtra(KEY_ENTRY));
mEntry = db.pm.entries.get(uuid);
if (mEntry == null) {
Toast.makeText(this, R.string.entry_not_found, Toast.LENGTH_LONG).show();
finish();
return;
}
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
ActivityCompat.invalidateOptionsMenu(this);
// Update last access time.
mEntry.touch(false, false);
// Get views
titleIconView = (ImageView) findViewById(R.id.entry_icon);
titleView = (TextView) findViewById(R.id.entry_title);
entryContentsView = (EntryContentsView) findViewById(R.id.entry_contents);
entryContentsView.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this));
fillData();
// Setup Edit Buttons
View edit = findViewById(R.id.entry_edit);
edit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EntryEditActivity.Launch(EntryActivity.this, mEntry);
}
});
if (readOnly) {
edit.setVisibility(View.GONE);
}
// If notifications enabled in settings
if (isClipboardNotificationsEnable(getApplicationContext())) {
// Notification Manager
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (mEntry.getPassword().length() > 0) {
// only show notification if password is available
Notification password = getNotification(Intents.COPY_PASSWORD, R.string.copy_password);
mNM.notify(NOTIFY_PASSWORD, password);
}
if (mEntry.getUsername().length() > 0) {
// only show notification if username is available
Notification username = getNotification(Intents.COPY_USERNAME, R.string.copy_username);
mNM.notify(NOTIFY_USERNAME, username);
}
}
mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ( action != null) {
if (action.equals(Intents.COPY_USERNAME)) {
String username = mEntry.getUsername();
if (username.length() > 0) {
timeoutCopyToClipboard(username);
}
} else if (action.equals(Intents.COPY_PASSWORD)) {
String password = mEntry.getPassword();
if (password.length() > 0) {
timeoutCopyToClipboard(password);
}
}
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intents.COPY_USERNAME);
filter.addAction(Intents.COPY_PASSWORD);
registerReceiver(mIntentReceiver, filter);
}
@Override
protected void onDestroy() {
// These members might never get initialized if the app timed out
if ( mIntentReceiver != null ) {
unregisterReceiver(mIntentReceiver);
}
if ( mNM != null ) {
try {
mNM.cancelAll();
} catch (SecurityException e) {
// Some android devices give a SecurityException when trying to cancel notifications without the WAKE_LOCK permission,
// we'll ignore these.
}
}
super.onDestroy();
}
private Notification getNotification(String intentText, int descResId) {
String desc = getString(descResId);
Intent intent = new Intent(intentText);
PendingIntent pending = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// no longer supported for api level >22
// notify.setLatestEventInfo(this, getString(R.string.app_name), desc, pending);
// so instead using compat builder and create new notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Notification notify = builder.setContentIntent(pending).setContentText(desc).setContentTitle(getString(R.string.app_name))
.setSmallIcon(R.drawable.notify).setTicker(desc).setWhen(System.currentTimeMillis()).build();
return notify;
}
private void populateTitle(Drawable drawIcon, String text) {
titleIconView.setImageDrawable(drawIcon);
titleView.setText(text);
}
protected void fillData() {
Database db = App.getDB();
PwDatabase pm = db.pm;
// Assign title
populateTitle(db.drawFactory.getIconDrawable(getResources(), mEntry.getIcon()),
mEntry.getTitle(true, pm));
// Assign basic fields
entryContentsView.assignUserName(mEntry.getUsername(true, pm));
entryContentsView.assignUserNameCopyListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
timeoutCopyToClipboard(mEntry.getUsername(true, App.getDB().pm),
getString(R.string.copy_field, getString(R.string.entry_user_name)));
}
});
entryContentsView.assignPassword(mEntry.getPassword(true, pm));
entryContentsView.assignPasswordCopyListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
timeoutCopyToClipboard(mEntry.getPassword(true, App.getDB().pm),
getString(R.string.copy_field, getString(R.string.entry_password)));
}
});
entryContentsView.assignURL(mEntry.getUrl(true, pm));
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
entryContentsView.assignComment(mEntry.getNotes(true, pm));
// Assign custom fields
if (mEntry.allowExtraFields()) {
entryContentsView.clearExtraFields();
for (Map.Entry<String, String> field : mEntry.getExtraFields(pm).entrySet()) {
final String label = field.getKey();
final String value = field.getValue();
entryContentsView.addExtraField(label, value, new View.OnClickListener() {
@Override
public void onClick(View view) {
timeoutCopyToClipboard(value, getString(R.string.copy_field, label));
}
});
}
}
// Assign dates
entryContentsView.assignCreationDate(mEntry.getCreationTime());
entryContentsView.assignModificationDate(mEntry.getLastModificationTime());
entryContentsView.assignLastAccessDate(mEntry.getLastAccessTime());
Date expires = mEntry.getExpiryTime();
if ( mEntry.expires() ) {
entryContentsView.assignExpiresDate(expires);
} else {
entryContentsView.assignExpiresDate(getString(R.string.never));
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE:
fillData();
break;
}
}
private void changeShowPasswordIcon(MenuItem togglePassword) {
if ( mShowPassword ) {
togglePassword.setTitle(R.string.menu_hide_password);
togglePassword.setIcon(R.drawable.ic_visibility_off_white_24dp);
} else {
togglePassword.setTitle(R.string.menu_showpass);
togglePassword.setIcon(R.drawable.ic_visibility_white_24dp);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
MenuUtil.donationMenuInflater(inflater, menu);
inflater.inflate(R.menu.entry, menu);
inflater.inflate(R.menu.database_lock, menu);
MenuItem togglePassword = menu.findItem(R.id.menu_toggle_pass);
if (!entryContentsView.isPasswordPresent()) {
togglePassword.setVisible(false);
} else {
changeShowPasswordIcon(togglePassword);
}
MenuItem gotoUrl = menu.findItem(R.id.menu_goto_url);
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
// so mEntry may not be set
if (mEntry == null) {
gotoUrl.setVisible(false);
}
else {
String url = mEntry.getUrl();
if (EmptyUtils.isNullOrEmpty(url)) {
// disable button if url is not available
gotoUrl.setVisible(false);
}
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.menu_donate:
return MenuUtil.onDonationItemSelected(this);
case R.id.menu_toggle_pass:
mShowPassword = !mShowPassword;
changeShowPasswordIcon(item);
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
return true;
case R.id.menu_goto_url:
String url;
url = mEntry.getUrl();
// Default http:// if no protocol specified
if ( ! url.contains("://") ) {
url = "http://" + url;
}
try {
Util.gotoUrl(this, url);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show();
}
return true;
case R.id.menu_lock:
App.setShutdown();
setResult(PasswordActivity.RESULT_EXIT_LOCK);
finish();
return true;
case android.R.id.home :
finish(); // close this activity and return to preview activity (if there is any)
}
return super.onOptionsItemSelected(item);
}
private void timeoutCopyToClipboard(String text) {
timeoutCopyToClipboard(text, "");
}
private void timeoutCopyToClipboard(String text, String toastString) {
if (!toastString.isEmpty())
Toast.makeText(EntryActivity.this, toastString, Toast.LENGTH_LONG).show();
try {
Util.copyToClipboard(this, text);
} catch (SamsungClipboardException e) {
showSamsungDialog();
return;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String sClipClear = prefs.getString(getString(R.string.clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
long clipClearTime = Long.parseLong(sClipClear);
if ( clipClearTime > 0 ) {
mTimer.schedule(new ClearClipboardTask(this, text), clipClearTime);
}
}
@Override
public void finish() {
// Transit data in previous Activity after an update
/*
TODO Slowdown when add entry as result
Intent intent = new Intent();
intent.putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry);
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, intent);
*/
super.finish();
}
// Setup to allow the toast to happen in the foreground
final Handler uiThreadCallback = new Handler();
// Task which clears the clipboard, and sends a toast to the foreground.
private class ClearClipboardTask extends TimerTask {
private final String mClearText;
private final Context mCtx;
ClearClipboardTask(Context ctx, String clearText) {
mClearText = clearText;
mCtx = ctx;
}
@Override
public void run() {
String currentClip = Util.getClipboard(mCtx);
if ( currentClip.equals(mClearText) ) {
try {
Util.copyToClipboard(mCtx, "");
uiThreadCallback.post(new UIToastTask(mCtx, R.string.ClearClipboard));
} catch (SamsungClipboardException e) {
uiThreadCallback.post(new UIToastTask(mCtx, R.string.clipboard_error_clear));
}
}
}
}
private void showSamsungDialog() {
String text = getString(R.string.clipboard_error).concat(System.getProperty("line.separator")).concat(getString(R.string.clipboard_error_url));
SpannableString s = new SpannableString(text);
TextView tv = new TextView(this);
tv.setText(s);
tv.setAutoLinkMask(RESULT_OK);
tv.setMovementMethod(LinkMovementMethod.getInstance());
Linkify.addLinks(s, Linkify.WEB_URLS);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.clipboard_error_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setView(tv)
.show();
}
}

View File

@@ -1,413 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.app.App;
import com.keepassdroid.database.Database;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV4;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupId;
import com.keepassdroid.database.PwIconStandard;
import com.keepassdroid.database.edit.AddEntry;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.RunnableOnFinish;
import com.keepassdroid.database.edit.UpdateEntry;
import com.keepassdroid.database.security.ProtectedString;
import com.keepassdroid.fragments.GeneratePasswordDialogFragment;
import com.keepassdroid.fragments.IconPickerDialogFragment;
import com.keepassdroid.icons.Icons;
import com.keepassdroid.settings.PreferencesUtil;
import com.keepassdroid.tasks.ProgressTask;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.utils.Types;
import com.keepassdroid.utils.Util;
import com.keepassdroid.view.EntryEditNewField;
import com.kunzisoft.keepass.R;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
public class EntryEditActivity extends LockingHideActivity
implements IconPickerDialogFragment.IconPickerListener,
GeneratePasswordDialogFragment.GeneratePasswordListener {
// Keys for current Activity
public static final String KEY_ENTRY = "entry";
public static final String KEY_PARENT = "parent";
// Keys for callback
public static final int ADD_ENTRY_RESULT_CODE = 31;
public static final int UPDATE_ENTRY_RESULT_CODE = 32;
public static final int ADD_OR_UPDATE_ENTRY_REQUEST_CODE = 7129;
public static final String ADD_OR_UPDATE_ENTRY_KEY = "ADD_OR_UPDATE_ENTRY_KEY";
protected PwEntry mEntry;
protected PwEntry mCallbackNewEntry;
protected boolean mIsNew;
protected int mSelectedIconID = -1;
// Views
private ScrollView scrollView;
private TextView entryTitleView;
private TextView entryUserNameView;
private TextView entryUrlView;
private TextView entryPasswordView;
private TextView entryConfirmationPasswordView;
private TextView entryCommentView;
private ViewGroup entryExtraFieldsContainer;
/**
* launch EntryEditActivity to update an existing entry
* @param act from activity
* @param pw Entry to update
*/
public static void Launch(Activity act, PwEntry pw) {
Intent intent = new Intent(act, EntryEditActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
/**
* launch EntryEditActivity to add a new entry
* @param act from activity
* @param pwGroup Group who will contains new entry
*/
public static void Launch(Activity act, PwGroup pwGroup) {
Intent intent = new Intent(act, EntryEditActivity.class);
intent.putExtra(KEY_PARENT, pwGroup.getId());
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_edit);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.app_name));
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
scrollView = (ScrollView) findViewById(R.id.entry_scroll);
scrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
entryTitleView = (TextView) findViewById(R.id.entry_title);
entryUserNameView = (TextView) findViewById(R.id.entry_user_name);
entryUrlView = (TextView) findViewById(R.id.entry_url);
entryPasswordView = (TextView) findViewById(R.id.entry_password);
entryConfirmationPasswordView = (TextView) findViewById(R.id.entry_confpassword);
entryCommentView = (TextView) findViewById(R.id.entry_comment);
entryExtraFieldsContainer = (ViewGroup) findViewById(R.id.advanced_container);
// Likely the app has been killed exit the activity
Database db = App.getDB();
if ( ! db.Loaded() ) {
finish();
return;
}
Intent intent = getIntent();
byte[] uuidBytes = intent.getByteArrayExtra(KEY_ENTRY);
PwDatabase pm = db.pm;
if ( uuidBytes == null ) {
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
PwGroup parent = pm.groups.get(parentId);
mEntry = PwEntry.getInstance(parent);
mIsNew = true;
} else {
UUID uuid = Types.bytestoUUID(uuidBytes);
mEntry = pm.entries.get(uuid);
mIsNew = false;
fillData();
}
View iconButton = findViewById(R.id.icon_button);
iconButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
IconPickerDialogFragment.launch(EntryEditActivity.this);
}
});
// Generate password button
View generatePassword = findViewById(R.id.generate_button);
generatePassword.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
GeneratePasswordDialogFragment generatePasswordDialogFragment = new GeneratePasswordDialogFragment();
generatePasswordDialogFragment.show(getSupportFragmentManager(), "PasswordGeneratorFragment");
}
});
// Save button
View save = findViewById(R.id.entry_save);
save.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!validateBeforeSaving()) {
return;
}
mCallbackNewEntry = populateNewEntry();
OnFinish onFinish = new AfterSave();
EntryEditActivity act = EntryEditActivity.this;
RunnableOnFinish task;
if ( mIsNew ) {
task = new AddEntry(act, App.getDB(), mCallbackNewEntry, onFinish);
} else {
task = new UpdateEntry(act, App.getDB(), mEntry, mCallbackNewEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
}
});
if (mEntry.allowExtraFields()) {
View add = findViewById(R.id.add_new_field);
add.setVisibility(View.VISIBLE);
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EntryEditNewField ees = new EntryEditNewField(EntryEditActivity.this);
ees.setData("", new ProtectedString(false, ""));
entryExtraFieldsContainer.addView(ees);
// Scroll bottom
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
});
}
}
protected boolean validateBeforeSaving() {
// Require title
String title = entryTitleView.getText().toString();
if ( title.length() == 0 ) {
Toast.makeText(this, R.string.error_title_required, Toast.LENGTH_LONG).show();
return false;
}
// Validate password
String pass = entryPasswordView.getText().toString();
String conf = entryConfirmationPasswordView.getText().toString();
if ( ! pass.equals(conf) ) {
Toast.makeText(this, R.string.error_pass_match, Toast.LENGTH_LONG).show();
return false;
}
// Validate extra fields
if (mEntry.allowExtraFields()) {
for (int i = 0; i < entryExtraFieldsContainer.getChildCount(); i++) {
EntryEditNewField entryEditNewField = (EntryEditNewField) entryExtraFieldsContainer.getChildAt(i);
String key = entryEditNewField.getLabel();
if (key == null || key.length() == 0) {
Toast.makeText(this, R.string.error_string_key, Toast.LENGTH_LONG).show();
return false;
}
}
}
return true;
}
protected PwEntry populateNewEntry() {
if (mEntry instanceof PwEntryV4) {
// TODO backup
PwEntryV4 newEntry = (PwEntryV4) mEntry.clone(true);
newEntry.history = (ArrayList<PwEntryV4>) newEntry.history.clone();
newEntry.createBackup((PwDatabaseV4) App.getDB().pm);
}
PwEntry newEntry = mEntry.clone(true);
Date now = Calendar.getInstance().getTime();
newEntry.setLastAccessTime(now);
newEntry.setLastModificationTime(now);
PwDatabase db = App.getDB().pm;
newEntry.setTitle(entryTitleView.getText().toString(), db);
if(mSelectedIconID != -1)
// or TODO icon factory newEntry.setIcon(App.getDB().pm.iconFactory.getIcon(mSelectedIconID));
newEntry.setIcon(new PwIconStandard(mSelectedIconID));
else {
if (mIsNew) {
newEntry.setIcon(App.getDB().pm.iconFactory.getIcon(0));
}
else {
// Keep previous icon, if no new one was selected
newEntry.setIcon(mEntry.icon);
}
}
newEntry.setUrl(entryUrlView.getText().toString(), db);
newEntry.setUsername(entryUserNameView.getText().toString(), db);
newEntry.setNotes(entryCommentView.getText().toString(), db);
newEntry.setPassword(entryPasswordView.getText().toString(), db);
if (newEntry.allowExtraFields()) {
// Delete all new standard strings
newEntry.removeExtraFields();
// Add extra fields from views
for (int i = 0; i < entryExtraFieldsContainer.getChildCount(); i++) {
EntryEditNewField view = (EntryEditNewField) entryExtraFieldsContainer.getChildAt(i);
String key = view.getLabel();
String value = view.getValue();
boolean protect = view.isProtected();
newEntry.addField(key, new ProtectedString(protect, value));
}
}
return newEntry;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
MenuUtil.donationMenuInflater(inflater, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.menu_donate:
return MenuUtil.onDonationItemSelected(this);
case android.R.id.home:
finish();
}
return super.onOptionsItemSelected(item);
}
protected void fillData() {
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
App.getDB().drawFactory.assignDrawableTo(currIconButton, getResources(), mEntry.getIcon());
boolean visibilityFont = PreferencesUtil.fieldFontIsInVisibility(this);
entryTitleView.setText(mEntry.getTitle());
entryUserNameView.setText(mEntry.getUsername());
entryUrlView.setText(mEntry.getUrl());
String password = mEntry.getPassword();
entryPasswordView.setText(password);
entryConfirmationPasswordView.setText(password);
entryCommentView.setText(mEntry.getNotes());
Util.applyFontVisibilityToTextView(visibilityFont, entryCommentView);
if (mEntry.allowExtraFields()) {
LinearLayout container = (LinearLayout) findViewById(R.id.advanced_container);
for (Map.Entry<String, ProtectedString> pair : mEntry.getExtraProtectedFields().entrySet()) {
EntryEditNewField entryEditNewField = new EntryEditNewField(EntryEditActivity.this);
entryEditNewField.setData(pair.getKey(), pair.getValue());
entryEditNewField.setFontVisibility(visibilityFont);
container.addView(entryEditNewField);
}
}
}
@Override
public void iconPicked(Bundle bundle) {
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
currIconButton.setImageResource(Icons.iconToResId(mSelectedIconID));
}
@Override
public void acceptPassword(Bundle bundle) {
String generatedPassword = bundle.getString(GeneratePasswordDialogFragment.KEY_PASSWORD_ID);
entryPasswordView.setText(generatedPassword);
entryConfirmationPasswordView.setText(generatedPassword);
}
@Override
public void cancelPassword(Bundle bundle) {
// Do nothing here
}
@Override
public void finish() {
// Assign entry callback as a result in all case
if (mCallbackNewEntry != null) {
Intent intentEntry = new Intent();
if (mIsNew) {
intentEntry.putExtra(ADD_OR_UPDATE_ENTRY_KEY, mCallbackNewEntry);
setResult(ADD_ENTRY_RESULT_CODE, intentEntry);
} else {
intentEntry.putExtra(ADD_OR_UPDATE_ENTRY_KEY, mCallbackNewEntry);
setResult(UPDATE_ENTRY_RESULT_CODE, intentEntry);
}
}
super.finish();
}
private final class AfterSave extends OnFinish {
AfterSave() {
super(new Handler());
}
@Override
public void run() {
if ( mSuccess ) {
finish();
} else {
displayMessage(EntryEditActivity.this);
}
}
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.activities;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.keepassdroid.app.App;
import com.keepassdroid.settings.PreferencesUtil;
import com.keepassdroid.stylish.StylishActivity;
import com.keepassdroid.timeout.TimeoutHelper;
public abstract class LockingActivity extends StylishActivity {
private ScreenReceiver screenReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this)) {
screenReceiver = new ScreenReceiver();
registerReceiver(screenReceiver, new IntentFilter((Intent.ACTION_SCREEN_OFF)));
} else
screenReceiver = null;
}
@Override
protected void onResume() {
super.onResume();
TimeoutHelper.checkShutdown(this);
TimeoutHelper.recordTime(this);
}
@Override
protected void onPause() {
super.onPause();
TimeoutHelper.checkTime(this);
TimeoutHelper.checkShutdown(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(screenReceiver != null)
unregisterReceiver(screenReceiver);
}
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(LockingActivity.this)) {
App.setShutdown();
TimeoutHelper.checkShutdown(LockingActivity.this);
}
}
}
}
}
}

View File

@@ -1,17 +0,0 @@
package com.keepassdroid.adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
abstract class BasicViewHolder extends RecyclerView.ViewHolder {
View container;
ImageView icon;
TextView text;
BasicViewHolder(View itemView) {
super(itemView);
}
}

View File

@@ -1,17 +0,0 @@
package com.keepassdroid.adapters;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kunzisoft.keepass.R;
class EntryViewHolder extends BasicViewHolder {
EntryViewHolder(View itemView) {
super(itemView);
container = itemView.findViewById(R.id.entry_container);
icon = (ImageView) itemView.findViewById(R.id.entry_icon);
text = (TextView) itemView.findViewById(R.id.entry_text);
}
}

View File

@@ -1,17 +0,0 @@
package com.keepassdroid.adapters;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kunzisoft.keepass.R;
class GroupViewHolder extends BasicViewHolder {
GroupViewHolder(View itemView) {
super(itemView);
container = itemView.findViewById(R.id.group_container);
icon = (ImageView) itemView.findViewById(R.id.group_icon);
text = (TextView) itemView.findViewById(R.id.group_text);
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.compat;
import java.lang.reflect.Method;
import android.app.Activity;
public class ActivityCompat {
private static Method invalidateOptMenu;
static {
try {
invalidateOptMenu = Activity.class.getMethod("invalidateOptionsMenu", (Class<Activity>[]) null);
} catch (Exception e) {
// Do nothing if method dosen't exist
}
}
public static void invalidateOptionsMenu(Activity act) {
if (invalidateOptMenu != null) {
try {
invalidateOptMenu.invoke(act, (Object[]) null);
} catch (Exception e) {
// Do nothing
}
}
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2017 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid 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.
*
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.compat;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.spec.AlgorithmParameterSpec;
public class KeyGenParameterSpecCompat {
private static Class builder;
private static Constructor buildConst;
private static Method builderBuild;
private static Method setBlockModes;
private static Method setUserAuthReq;
private static Method setEncPad;
private static boolean available;
static {
try {
builder = Class.forName("android.security.keystore.KeyGenParameterSpec$Builder");
buildConst = builder.getConstructor(String.class, int.class);
builderBuild = builder.getMethod("build", (Class [])null);
setBlockModes = builder.getMethod("setBlockModes", String[].class);
setUserAuthReq = builder.getMethod("setUserAuthenticationRequired", new Class []{boolean.class});
setEncPad = builder.getMethod("setEncryptionPaddings", String[].class);
available = true;
} catch (Exception e) {
available = false;
}
}
public static AlgorithmParameterSpec build(String keystoreAlias, int purpose, String blockMode,
boolean userAuthReq, String encPadding) {
if (!available) {
return null;
}
try {
Object inst = buildConst.newInstance(keystoreAlias, purpose);
inst = setBlockModes.invoke(inst, new Object[] {new String[] {blockMode}});
inst = setUserAuthReq.invoke(inst, userAuthReq);
inst = setEncPad.invoke(inst, new Object[] {new String[] {encPadding}});
return (AlgorithmParameterSpec) builderBuild.invoke(inst, null);
} catch (Exception e) {
return null;
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2017 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid 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.
*
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.compat;
import android.app.KeyguardManager;
import java.lang.reflect.Method;
public class KeyguardManagerCompat {
private static Method isKeyguardSecure;
private static boolean available;
static {
try {
isKeyguardSecure = KeyguardManager.class.getMethod("isKeyguardSecure", (Class[]) null);
available = true;
} catch (Exception e) {
available = false;
}
}
public static boolean isKeyguardSecure(KeyguardManager inst) {
if (!available) {
return false;
}
try {
return (boolean) isKeyguardSecure.invoke(inst, null);
} catch (Exception e) {
return false;
}
}
}

View File

@@ -1,227 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;
import com.keepassdroid.database.exception.ContentFileNotFoundException;
import com.keepassdroid.database.exception.InvalidDBException;
import com.keepassdroid.database.exception.InvalidPasswordException;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.load.Importer;
import com.keepassdroid.database.load.ImporterFactory;
import com.keepassdroid.database.save.PwDbOutput;
import com.keepassdroid.icons.DrawableFactory;
import com.keepassdroid.search.SearchDbHelper;
import com.keepassdroid.tasks.UpdateStatus;
import com.keepassdroid.utils.UriUtil;
import com.kunzisoft.keepass.R;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SyncFailedException;
/**
* @author bpellin
*/
public class Database {
public PwDatabase pm;
public Uri mUri;
public SearchDbHelper searchHelper;
public boolean readOnly = false;
public boolean passwordEncodingError = false;
public DrawableFactory drawFactory = new DrawableFactory();
private boolean loaded = false;
public boolean Loaded() {
return loaded;
}
public void setLoaded() {
loaded = true;
}
public void LoadData(Context ctx, InputStream is, String password, InputStream keyInputStream) throws IOException, InvalidDBException {
LoadData(ctx, is, password, keyInputStream, new UpdateStatus(), !Importer.DEBUG);
}
public void LoadData(Context ctx, Uri uri, String password, Uri keyfile) throws IOException, FileNotFoundException, InvalidDBException {
LoadData(ctx, uri, password, keyfile, new UpdateStatus(), !Importer.DEBUG);
}
public void LoadData(Context ctx, Uri uri, String password, Uri keyfile, UpdateStatus status) throws IOException, FileNotFoundException, InvalidDBException {
LoadData(ctx, uri, password, keyfile, status, !Importer.DEBUG);
}
public void LoadData(Context ctx, Uri uri, String password, Uri keyfile, UpdateStatus status, boolean debug) throws IOException, FileNotFoundException, InvalidDBException {
mUri = uri;
readOnly = false;
if (uri.getScheme().equals("file")) {
File file = new File(uri.getPath());
readOnly = !file.canWrite();
}
try {
passUrisAsInputStreams(ctx, uri, password, keyfile, status, debug, 0);
} catch (InvalidPasswordException e) {
// Retry with rounds fix
try {
passUrisAsInputStreams(ctx, uri, password, keyfile, status, debug, getFixRounds(ctx));
} catch (Exception e2) {
// Rethrow original exception
throw e;
}
}
}
private long getFixRounds(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return prefs.getLong(ctx.getString(R.string.roundsFix_key), ctx.getResources().getInteger(R.integer.roundsFix_default));
}
private void passUrisAsInputStreams(Context ctx, Uri uri, String password, Uri keyfile, UpdateStatus status, boolean debug, long roundsFix) throws IOException, FileNotFoundException, InvalidDBException {
InputStream is, kfIs;
try {
is = UriUtil.getUriInputStream(ctx, uri);
} catch (Exception e) {
Log.e("KPD", "Database::LoadData", e);
throw ContentFileNotFoundException.getInstance(uri);
}
try {
kfIs = UriUtil.getUriInputStream(ctx, keyfile);
} catch (Exception e) {
Log.e("KPD", "Database::LoadData", e);
throw ContentFileNotFoundException.getInstance(keyfile);
}
LoadData(ctx, is, password, kfIs, status, debug, roundsFix);
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, boolean debug) throws IOException, InvalidDBException {
LoadData(ctx, is, password, kfIs, new UpdateStatus(), debug);
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, UpdateStatus status, boolean debug) throws IOException, InvalidDBException {
LoadData(ctx, is, password, kfIs, status, debug, 0);
}
public void LoadData(Context ctx, InputStream is, String password, InputStream kfIs, UpdateStatus status, boolean debug, long roundsFix) throws IOException, InvalidDBException {
BufferedInputStream bis = new BufferedInputStream(is);
if ( ! bis.markSupported() ) {
throw new IOException("Input stream does not support mark.");
}
// We'll end up reading 8 bytes to identify the header. Might as well use two extra.
bis.mark(10);
Importer imp = ImporterFactory.createImporter(bis, debug);
bis.reset(); // Return to the start
pm = imp.openDatabase(bis, password, kfIs, status, roundsFix);
if ( pm != null ) {
PwGroup root = pm.rootGroup;
pm.populateGlobals(root);
LoadData(ctx, pm, password, kfIs, status);
}
loaded = true;
}
public void LoadData(Context ctx, PwDatabase pm, String password, InputStream keyInputStream, UpdateStatus status) {
if ( pm != null ) {
passwordEncodingError = !pm.validatePasswordEncoding(password);
}
searchHelper = new SearchDbHelper(ctx);
loaded = true;
}
public PwGroup Search(String str) {
if (searchHelper == null) { return null; }
return searchHelper.search(this, str);
}
public void SaveData(Context ctx) throws IOException, PwDbOutputException {
SaveData(ctx, mUri);
}
public void SaveData(Context ctx, Uri uri) throws IOException, PwDbOutputException {
if (uri.getScheme().equals("file")) {
String filename = uri.getPath();
File tempFile = new File(filename + ".tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
//BufferedOutputStream bos = new BufferedOutputStream(fos);
//PwDbV3Output pmo = new PwDbV3Output(pm, bos, App.getCalendar());
PwDbOutput pmo = PwDbOutput.getInstance(pm, fos);
pmo.output();
//bos.flush();
//bos.close();
fos.close();
// Force data to disk before continuing
try {
fos.getFD().sync();
} catch (SyncFailedException e) {
// Ignore if fsync fails. We tried.
}
File orig = new File(filename);
if (!tempFile.renameTo(orig)) {
throw new IOException("Failed to store database.");
}
}
else {
OutputStream os;
try {
os = ctx.getContentResolver().openOutputStream(uri);
} catch (Exception e) {
throw new IOException("Failed to store database.");
}
PwDbOutput pmo = PwDbOutput.getInstance(pm, os);
pmo.output();
os.close();
}
mUri = uri;
}
public void clear() {
drawFactory.clear();
pm = null;
mUri = null;
loaded = false;
passwordEncodingError = false;
}
}

View File

@@ -1,115 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import java.util.Date;
import java.util.List;
import com.keepassdroid.database.iterator.EntrySearchStringIterator;
public abstract class EntrySearchHandler extends EntryHandler<PwEntry> {
private List<PwEntry> listStorage;
private SearchParameters sp;
private Date now;
public static EntrySearchHandler getInstance(PwGroup group, SearchParameters sp, List<PwEntry> listStorage) {
if (group instanceof PwGroupV3) {
return new EntrySearchHandlerV4(sp, listStorage);
} else if (group instanceof PwGroupV4) {
return new EntrySearchHandlerV4(sp, listStorage);
} else {
throw new RuntimeException("Not implemented.");
}
}
protected EntrySearchHandler(SearchParameters sp, List<PwEntry> listStorage) {
this.sp = sp;
this.listStorage = listStorage;
now = new Date();
}
@Override
public boolean operate(PwEntry entry) {
if (sp.respectEntrySearchingDisabled && !entry.isSearchingEnabled()) {
return true;
}
if (sp.excludeExpired && entry.expires() && now.after(entry.getExpiryTime())) {
return true;
}
String term = sp.searchString;
if (sp.ignoreCase) {
term = term.toLowerCase();
}
if (searchStrings(entry, term)) {
listStorage.add(entry);
return true;
}
if (sp.searchInGroupNames) {
PwGroup parent = entry.getParent();
if (parent != null) {
String groupName = parent.getName();
if (groupName != null) {
if (sp.ignoreCase) {
groupName = groupName.toLowerCase();
}
if (groupName.indexOf(term) >= 0) {
listStorage.add(entry);
return true;
}
}
}
}
if (searchID(entry)) {
listStorage.add(entry);
return true;
}
return true;
}
protected boolean searchID(PwEntry entry) {
return false;
}
private boolean searchStrings(PwEntry entry, String term) {
EntrySearchStringIterator iter = EntrySearchStringIterator.getInstance(entry, sp);
while (iter.hasNext()) {
String str = iter.next();
if (str != null & str.length() > 0) {
if (sp.ignoreCase) {
str = str.toLowerCase();
}
if (str.indexOf(term) >= 0) {
return true;
}
}
}
return false;
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import com.keepassdroid.utils.StrUtil;
import com.keepassdroid.utils.UuidUtil;
import java.util.List;
import java.util.Locale;
public class EntrySearchHandlerV4 extends EntrySearchHandler {
private SearchParametersV4 sp;
protected EntrySearchHandlerV4(SearchParameters sp, List<PwEntry> listStorage) {
super(sp, listStorage);
this.sp = (SearchParametersV4) sp;
}
@Override
protected boolean searchID(PwEntry e) {
PwEntryV4 entry = (PwEntryV4) e;
if (sp.searchInUUIDs) {
String hex = UuidUtil.toHexString(entry.uuid);
return StrUtil.indexOfIgnoreCase(hex, sp.searchString, Locale.ENGLISH) >= 0;
}
return false;
}
}

View File

@@ -1,563 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import android.webkit.URLUtil;
import com.keepassdroid.collections.VariantDictionary;
import com.keepassdroid.crypto.CryptoUtil;
import com.keepassdroid.crypto.engine.AesEngine;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.AesKdf;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.crypto.keyDerivation.KdfParameters;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.utils.EmptyUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import biz.source_code.base64Coder.Base64Coder;
public class PwDatabaseV4 extends PwDatabase {
public static final Date DEFAULT_NOW = new Date();
public static final UUID UUID_ZERO = new UUID(0,0);
public static final int DEFAULT_ROUNDS = 6000;
private static final int DEFAULT_HISTORY_MAX_ITEMS = 10; // -1 unlimited
private static final long DEFAULT_HISTORY_MAX_SIZE = 6 * 1024 * 1024; // -1 unlimited
private static final String RECYCLEBIN_NAME = "RecycleBin";
public byte[] hmacKey;
public UUID dataCipher = AesEngine.CIPHER_UUID;
public CipherEngine dataEngine = new AesEngine();
public PwCompressionAlgorithm compressionAlgorithm = PwCompressionAlgorithm.Gzip;
// TODO: Refactor me away to get directly from kdfParameters
public long numKeyEncRounds = 6000;
public Date nameChanged = DEFAULT_NOW;
public Date settingsChanged = DEFAULT_NOW;
public String description = "";
public Date descriptionChanged = DEFAULT_NOW;
public String defaultUserName = "";
public Date defaultUserNameChanged = DEFAULT_NOW;
public Date keyLastChanged = DEFAULT_NOW;
public long keyChangeRecDays = -1;
public long keyChangeForceDays = 1;
public boolean keyChangeForceOnce = false;
public long maintenanceHistoryDays = 365;
public String color = "";
public boolean recycleBinEnabled = true;
public UUID recycleBinUUID = UUID_ZERO;
public Date recycleBinChanged = DEFAULT_NOW;
public UUID entryTemplatesGroup = UUID_ZERO;
public Date entryTemplatesGroupChanged = DEFAULT_NOW;
public int historyMaxItems = DEFAULT_HISTORY_MAX_ITEMS;
public long historyMaxSize = DEFAULT_HISTORY_MAX_SIZE;
public UUID lastSelectedGroup = UUID_ZERO;
public UUID lastTopVisibleGroup = UUID_ZERO;
public MemoryProtectionConfig memoryProtection = new MemoryProtectionConfig();
public List<PwDeletedObject> deletedObjects = new ArrayList<PwDeletedObject>();
public List<PwIconCustom> customIcons = new ArrayList<PwIconCustom>();
public Map<String, String> customData = new HashMap<String, String>();
public KdfParameters kdfParameters = KdfFactory.getDefaultParameters();
public VariantDictionary publicCustomData = new VariantDictionary();
public BinaryPool binPool = new BinaryPool();
public String localizedAppName = "KeePassDroid";
public class MemoryProtectionConfig {
public boolean protectTitle = false;
public boolean protectUserName = false;
public boolean protectPassword = false;
public boolean protectUrl = false;
public boolean protectNotes = false;
public boolean autoEnableVisualHiding = false;
public boolean GetProtection(String field) {
if ( field.equalsIgnoreCase(PwDefsV4.TITLE_FIELD)) return protectTitle;
if ( field.equalsIgnoreCase(PwDefsV4.USERNAME_FIELD)) return protectUserName;
if ( field.equalsIgnoreCase(PwDefsV4.PASSWORD_FIELD)) return protectPassword;
if ( field.equalsIgnoreCase(PwDefsV4.URL_FIELD)) return protectUrl;
if ( field.equalsIgnoreCase(PwDefsV4.NOTES_FIELD)) return protectNotes;
return false;
}
}
@Override
public byte[] getMasterKey(String key, InputStream keyInputStream)
throws InvalidKeyFileException, IOException {
assert(key != null);
byte[] fKey = new byte[]{};
if ( key.length() > 0 && keyInputStream != null) {
return getCompositeKey(key, keyInputStream);
} else if ( key.length() > 0 ) {
fKey = getPasswordKey(key);
} else if ( keyInputStream != null) {
fKey = getFileKey(keyInputStream);
}
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("No SHA-256 implementation");
}
return md.digest(fKey);
}
@Override
public void makeFinalKey(byte[] masterSeed, byte[] masterSeed2, int numRounds) throws IOException {
byte[] transformedMasterKey = transformMasterKey(masterSeed2, masterKey, numRounds);
byte[] cmpKey = new byte[65];
System.arraycopy(masterSeed, 0, cmpKey, 0, 32);
System.arraycopy(transformedMasterKey, 0, cmpKey, 32, 32);
finalKey = CryptoUtil.resizeKey(cmpKey, 0, 64, dataEngine.keyLength());
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-512");
cmpKey[64] = 1;
hmacKey = md.digest(cmpKey);
} catch (NoSuchAlgorithmException e) {
throw new IOException("No SHA-512 implementation");
} finally {
Arrays.fill(cmpKey, (byte)0);
}
}
public void makeFinalKey(byte[] masterSeed, KdfParameters kdfP) throws IOException {
makeFinalKey(masterSeed, kdfP, 0);
}
public void makeFinalKey(byte[] masterSeed, KdfParameters kdfP, long roundsFix)
throws IOException {
KdfEngine kdfEngine = KdfFactory.get(kdfP.kdfUUID);
if (kdfEngine == null) {
throw new IOException("Unknown key derivation function");
}
// Set to 6000 rounds to open corrupted database
if (roundsFix > 0 && kdfP.kdfUUID.equals(AesKdf.CIPHER_UUID)) {
kdfP.setUInt32(AesKdf.ParamRounds, roundsFix);
numKeyEncRounds = roundsFix;
}
byte[] transformedMasterKey = kdfEngine.transform(masterKey, kdfP);
if (transformedMasterKey.length != 32) {
transformedMasterKey = CryptoUtil.hashSha256(transformedMasterKey);
}
byte[] cmpKey = new byte[65];
System.arraycopy(masterSeed, 0, cmpKey, 0, 32);
System.arraycopy(transformedMasterKey, 0, cmpKey, 32, 32);
finalKey = CryptoUtil.resizeKey(cmpKey, 0, 64, dataEngine.keyLength());
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-512");
cmpKey[64] = 1;
hmacKey = md.digest(cmpKey);
} catch (NoSuchAlgorithmException e) {
throw new IOException("No SHA-512 implementation");
} finally {
Arrays.fill(cmpKey, (byte)0);
}
}
@Override
protected String getPasswordEncoding() {
return "UTF-8";
}
private static final String RootElementName = "KeyFile";
//private static final String MetaElementName = "Meta";
//private static final String VersionElementName = "Version";
private static final String KeyElementName = "Key";
private static final String KeyDataElementName = "Data";
@Override
protected byte[] loadXmlKeyFile(InputStream keyInputStream) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(keyInputStream);
Element el = doc.getDocumentElement();
if (el == null || ! el.getNodeName().equalsIgnoreCase(RootElementName)) {
return null;
}
NodeList children = el.getChildNodes();
if (children.getLength() < 2) {
return null;
}
for ( int i = 0; i < children.getLength(); i++ ) {
Node child = children.item(i);
if ( child.getNodeName().equalsIgnoreCase(KeyElementName) ) {
NodeList keyChildren = child.getChildNodes();
for ( int j = 0; j < keyChildren.getLength(); j++ ) {
Node keyChild = keyChildren.item(j);
if ( keyChild.getNodeName().equalsIgnoreCase(KeyDataElementName) ) {
NodeList children2 = keyChild.getChildNodes();
for ( int k = 0; k < children2.getLength(); k++) {
Node text = children2.item(k);
if (text.getNodeType() == Node.TEXT_NODE) {
Text txt = (Text) text;
return Base64Coder.decode(txt.getNodeValue());
}
}
}
}
}
}
} catch (Exception e) {
return null;
}
return null;
}
@Override
public List<PwGroup> getGroups() {
List<PwGroup> list = new ArrayList<PwGroup>();
PwGroupV4 root = (PwGroupV4) rootGroup;
root.buildChildGroupsRecursive(list);
return list;
}
@Override
public List<PwGroup> getGrpRoots() {
return rootGroup.childGroups;
}
@Override
public List<PwEntry> getEntries() {
List<PwEntry> list = new ArrayList<PwEntry>();
PwGroupV4 root = (PwGroupV4) rootGroup;
root.buildChildEntriesRecursive(list);
return list;
}
@Override
public long getNumRounds() {
return numKeyEncRounds;
}
@Override
public void setNumRounds(long rounds) throws NumberFormatException {
numKeyEncRounds = rounds;
}
@Override
public boolean algorithmSettingsEnabled() {
return false;
}
@Override
public PwEncryptionAlgorithm getEncAlgorithm() {
return PwEncryptionAlgorithm.Rjindal;
}
@Override
public PwGroupIdV4 newGroupId() {
PwGroupIdV4 id = new PwGroupIdV4(UUID_ZERO);
while (true) {
id = new PwGroupIdV4(UUID.randomUUID());
if (!isGroupIdUsed(id)) break;
}
return id;
}
@Override
public PwGroup createGroup() {
return new PwGroupV4();
}
@Override
public boolean isBackup(PwGroup group) {
if (!recycleBinEnabled) {
return false;
}
return group.isContainedIn(getRecycleBin());
}
@Override
public void populateGlobals(PwGroup currentGroup) {
groups.put(rootGroup.getId(), rootGroup);
super.populateGlobals(currentGroup);
}
/** Ensure that the recycle bin tree exists, if enabled and create it
* if it doesn't exist
*
*/
private void ensureRecycleBin() {
if (getRecycleBin() == null) {
// Create recycle bin
PwGroupV4 recycleBin = new PwGroupV4(true, true, RECYCLEBIN_NAME, iconFactory.getIcon(PwIconStandard.TRASH_BIN));
recycleBin.enableAutoType = false;
recycleBin.enableSearching = false;
recycleBin.isExpanded = false;
addGroupTo(recycleBin, rootGroup);
recycleBinUUID = recycleBin.uuid;
}
}
@Override
public boolean isRecycleBinAvailable() {
return true;
}
@Override
public boolean isRecycleBinEnable() {
return recycleBinEnabled;
}
@Override
public boolean canRecycle(PwGroup group) {
if (!recycleBinEnabled) {
return false;
}
PwGroup recycle = getRecycleBin();
return (recycle == null) || (!group.isContainedIn(recycle));
}
@Override
public boolean canRecycle(PwEntry entry) {
if (!recycleBinEnabled) {
return false;
}
PwGroup parent = entry.getParent();
return (parent != null) && canRecycle(parent);
}
@Override
public void recycle(PwGroup group) {
ensureRecycleBin();
PwGroup parent = group.getParent();
removeGroupFrom(group, parent);
parent.touch(false, true);
PwGroup recycleBin = getRecycleBin();
addGroupTo(group, recycleBin);
group.touch(false, true);
// TODO ? group.touchLocation();
}
@Override
public void recycle(PwEntry entry) {
ensureRecycleBin();
PwGroup parent = entry.getParent();
removeEntryFrom(entry, parent);
parent.touch(false, true);
PwGroup recycleBin = getRecycleBin();
addEntryTo(entry, recycleBin);
entry.touch(false, true);
entry.touchLocation();
}
@Override
public void undoRecycle(PwGroup group, PwGroup origParent) {
PwGroup recycleBin = getRecycleBin();
removeGroupFrom(group, recycleBin);
addGroupTo(group, origParent);
}
@Override
public void undoRecycle(PwEntry entry, PwGroup origParent) {
PwGroup recycleBin = getRecycleBin();
removeEntryFrom(entry, recycleBin);
addEntryTo(entry, origParent);
}
@Override
public void deleteEntry(PwEntry entry) {
super.deleteEntry(entry);
deletedObjects.add(new PwDeletedObject(entry.getUUID()));
}
@Override
public void undoDeleteEntry(PwEntry entry, PwGroup origParent) {
super.undoDeleteEntry(entry, origParent);
// TODO undo delete entry
deletedObjects.remove(entry);
}
@Override
public PwGroupV4 getRecycleBin() {
if (recycleBinUUID == null) {
return null;
}
PwGroupId recycleId = new PwGroupIdV4(recycleBinUUID);
return (PwGroupV4) groups.get(recycleId);
}
@Override
public boolean isGroupSearchable(PwGroup group, boolean omitBackup) {
if (!super.isGroupSearchable(group, omitBackup)) {
return false;
}
PwGroupV4 g = (PwGroupV4) group;
return g.isSearchEnabled();
}
@Override
public boolean validatePasswordEncoding(String key) {
return true;
}
@Override
public void initNew(String dbPath) {
String filename = URLUtil.guessFileName(dbPath, null, null);
rootGroup = new PwGroupV4(true, true, dbNameFromPath(dbPath), iconFactory.getIcon(PwIconStandard.FOLDER));
groups.put(rootGroup.getId(), rootGroup);
}
private String dbNameFromPath(String dbPath) {
String filename = URLUtil.guessFileName(dbPath, null, null);
if (EmptyUtils.isNullOrEmpty(filename)) {
return "KeePass Database";
}
int lastExtDot = filename.lastIndexOf(".");
if (lastExtDot == -1) {
return filename;
}
return filename.substring(0, lastExtDot);
}
private class GroupHasCustomData extends GroupHandler<PwGroup> {
public boolean hasCustomData = false;
@Override
public boolean operate(PwGroup group) {
if (group == null) {
return true;
}
PwGroupV4 g4 = (PwGroupV4) group;
if (g4.customData.size() > 0) {
hasCustomData = true;
return false;
}
return true;
}
}
private class EntryHasCustomData extends EntryHandler<PwEntry> {
public boolean hasCustomData = false;
@Override
public boolean operate(PwEntry entry) {
if (entry == null) {
return true;
}
PwEntryV4 e4 = (PwEntryV4)entry;
if (e4.customData.size() > 0) {
hasCustomData = true;
return false;
}
return true;
}
}
public int getMinKdbxVersion() {
if (!AesKdf.CIPHER_UUID.equals(kdfParameters.kdfUUID)) {
return PwDbHeaderV4.FILE_VERSION_32;
}
if (publicCustomData.size() > 0) {
return PwDbHeaderV4.FILE_VERSION_32;
}
EntryHasCustomData entryHandler = new EntryHasCustomData();
GroupHasCustomData groupHandler = new GroupHasCustomData();
if (rootGroup == null ) {
return PwDbHeaderV4.FILE_VERSION_32_3;
}
rootGroup.preOrderTraverseTree(groupHandler, entryHandler);
if (groupHandler.hasCustomData || entryHandler.hasCustomData) {
return PwDbHeaderV4.FILE_VERSION_32;
}
return PwDbHeaderV4.FILE_VERSION_32_3;
}
}

View File

@@ -1,290 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import com.keepassdroid.database.iterator.EntrySearchStringIterator;
import com.keepassdroid.database.security.ProtectedString;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public abstract class PwEntry extends PwNode implements Cloneable {
protected static final String PMS_TAN_ENTRY = "<TAN>";
public PwIconStandard icon = PwIconStandard.FIRST;
public static PwEntry getInstance(PwGroup parent) {
if (parent instanceof PwGroupV3) {
return new PwEntryV3((PwGroupV3)parent);
}
else if (parent instanceof PwGroupV4) {
return new PwEntryV4((PwGroupV4)parent);
}
else {
throw new RuntimeException("Unknown PwGroup instance.");
}
}
@Override
public Object clone() {
PwEntry newEntry;
try {
newEntry = (PwEntry) super.clone();
} catch (CloneNotSupportedException e) {
assert(false);
throw new RuntimeException("Clone should be supported");
}
return newEntry;
}
public PwEntry clone(boolean deepStrings) {
return (PwEntry) clone();
}
@Override
public Type getType() {
return Type.ENTRY;
}
public void assign(PwEntry source) {
icon = source.icon;
}
public abstract UUID getUUID();
public abstract void setUUID(UUID u);
public String getTitle() {
return getTitle(false, null);
}
public String getUsername() {
return getUsername(false, null);
}
public String getPassword() {
return getPassword(false, null);
}
public String getUrl() {
return getUrl(false, null);
}
public String getNotes() {
return getNotes(false, null);
}
public abstract String getTitle(boolean decodeRef, PwDatabase db);
public abstract String getUsername(boolean decodeRef, PwDatabase db);
public abstract String getPassword(boolean decodeRef, PwDatabase db);
public abstract String getUrl(boolean decodeRef, PwDatabase db);
public abstract String getNotes(boolean decodeRef, PwDatabase db);
public abstract Date getLastModificationTime();
public abstract Date getLastAccessTime();
public abstract Date getExpiryTime();
public abstract boolean expires();
public abstract void setTitle(String title, PwDatabase db);
public abstract void setUsername(String user, PwDatabase db);
public abstract void setPassword(String pass, PwDatabase db);
public abstract void setUrl(String url, PwDatabase db);
public abstract void setNotes(String notes, PwDatabase db);
public abstract void setCreationTime(Date create);
public abstract void setLastModificationTime(Date mod);
public abstract void setLastAccessTime(Date access);
public abstract void setExpires(boolean exp);
public abstract void setExpiryTime(Date expires);
public PwIcon getIcon() {
return icon;
}
public void setIcon(PwIconStandard icon) {
this.icon = icon;
}
public boolean isTan() {
return getTitle().equals(PMS_TAN_ENTRY) && (getUsername().length() > 0);
}
public String getDisplayTitle() {
if ( isTan() ) {
return PMS_TAN_ENTRY + " " + getUsername();
} else {
return getTitle();
}
}
// TODO encapsulate extra fields
/**
* To redefine if version of entry allow extra field,
* @return true if entry allows extra field
*/
public boolean allowExtraFields() {
return false;
}
/**
* Retrieve extra fields to show, key is the label, value is the value of field
* @param pm Database
* @return Map of label/value
*/
public Map<String, String> getExtraFields(PwDatabase pm) {
return new HashMap<>();
}
/**
* Retrieve extra protected fields to show, key is the label, value is the value protected of field
* @return Map of label/value
*/
public Map<String, ProtectedString> getExtraProtectedFields() {
return new HashMap<>();
}
/**
* Add an extra field to the list
* @param label Label of field, must be unique
* @param value Value of field
*/
public void addField(String label, ProtectedString value) {}
/**
* Delete all extra fields
*/
public void removeExtraFields() {}
/**
* If it's a node with only meta information like Meta-info SYSTEM Database Color
* @return false by default, true if it's a meta stream
*/
public boolean isMetaStream() {
return false;
}
public EntrySearchStringIterator stringIterator() {
return EntrySearchStringIterator.getInstance(this);
}
public void touch(boolean modified, boolean touchParents) {
Date now = new Date();
setLastAccessTime(now);
if (modified) {
setLastModificationTime(now);
}
PwGroup parent = getParent();
if (touchParents && parent != null) {
parent.touch(modified, true);
}
}
public void touchLocation() { }
public boolean isSearchingEnabled() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PwEntry pwEntry = (PwEntry) o;
return isSameType(pwEntry)
&& (getUUID() != null ? getUUID().equals(pwEntry.getUUID()) : pwEntry.getUUID() == null);
}
@Override
public int hashCode() {
return getUUID() != null ? getUUID().hashCode() : 0;
}
/**
* Comparator of Entry by Name
*/
public static class EntryNameComparator implements Comparator<PwEntry> {
private boolean ascending;
public EntryNameComparator() {
this(true);
}
public EntryNameComparator(boolean ascending) {
this.ascending = ascending;
}
public int compare(PwEntry object1, PwEntry object2) {
if (object1.equals(object2))
return 0;
int entryTitleComp = object1.getTitle().compareToIgnoreCase(object2.getTitle());
// If same title, can be different
if (entryTitleComp == 0) {
return object1.hashCode() - object2.hashCode();
}
// If descending
if (!ascending)
entryTitleComp = -entryTitleComp;
return entryTitleComp;
}
}
/**
* Comparator of Entry by Creation
*/
public static class EntryCreationComparator implements Comparator<PwEntry> {
private boolean ascending;
public EntryCreationComparator() {
this(true);
}
public EntryCreationComparator(boolean ascending) {
this.ascending = ascending;
}
public int compare(PwEntry object1, PwEntry object2) {
if (object1.equals(object2))
return 0;
int entryCreationComp = object1.getCreationTime().compareTo(object2.getCreationTime());
// If same creation, can be different
if (entryCreationComp == 0) {
return object1.hashCode() - object2.hashCode();
}
// If descending
if (!ascending)
entryCreationComp = -entryCreationComp;
return entryCreationComp;
}
}
}

View File

@@ -1,528 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
This file was derived from
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
This file was derived from
Java clone of KeePass - A KeePass file viewer for Java
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
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; version 2
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
*/
package com.keepassdroid.database;
// PhoneID
import com.keepassdroid.utils.Types;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
/**
* Structure containing information about one entry.
*
* <PRE>
* One entry: [FIELDTYPE(FT)][FIELDSIZE(FS)][FIELDDATA(FD)]
* [FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)]...
*
* [ 2 bytes] FIELDTYPE
* [ 4 bytes] FIELDSIZE, size of FIELDDATA in bytes
* [ n bytes] FIELDDATA, n = FIELDSIZE
*
* Notes:
* - Strings are stored in UTF-8 encoded form and are null-terminated.
* - FIELDTYPE can be one of the FT_ constants.
* </PRE>
*
* @author Naomaru Itoi <nao@phoneid.org>
* @author Bill Zwicky <wrzwicky@pobox.com>
* @author Dominik Reichl <dominik.reichl@t-online.de>
*/
public class PwEntryV3 extends PwEntry {
public static final Date NEVER_EXPIRE = getNeverExpire();
public static final Date NEVER_EXPIRE_BUG = getNeverExpireBug();
public static final Date DEFAULT_DATE = getDefaultDate();
public static final PwDate PW_NEVER_EXPIRE = new PwDate(NEVER_EXPIRE);
public static final PwDate PW_NEVER_EXPIRE_BUG = new PwDate(NEVER_EXPIRE_BUG);
public static final PwDate DEFAULT_PWDATE = new PwDate(DEFAULT_DATE);
/** Size of byte buffer needed to hold this struct. */
public static final String PMS_ID_BINDESC = "bin-stream";
public static final String PMS_ID_TITLE = "Meta-Info";
public static final String PMS_ID_USER = "SYSTEM";
public static final String PMS_ID_URL = "$";
public int groupId;
public String username;
private byte[] password;
private byte[] uuid;
public String title;
public String url;
public String additional;
public PwDate tCreation;
public PwDate tLastMod;
public PwDate tLastAccess;
public PwDate tExpire;
/** A string describing what is in pBinaryData */
public String binaryDesc;
private byte[] binaryData;
private static Date getDefaultDate() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2004);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
return cal.getTime();
}
private static Date getNeverExpire() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2999);
cal.set(Calendar.MONTH, 11);
cal.set(Calendar.DAY_OF_MONTH, 28);
cal.set(Calendar.HOUR, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
return cal.getTime();
}
/** This date was was accidentally being written
* out when an entry was supposed to be marked as
* expired. We'll use this to silently correct those
* entries.
* @return
*/
private static Date getNeverExpireBug() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2999);
cal.set(Calendar.MONTH, 11);
cal.set(Calendar.DAY_OF_MONTH, 30);
cal.set(Calendar.HOUR, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
return cal.getTime();
}
public static boolean IsNever(Date date) {
return PwDate.IsSameDate(NEVER_EXPIRE, date);
}
// for tree traversing
public PwGroupV3 parent = null;
public PwEntryV3() {
super();
}
/*
public PwEntryV3(PwEntryV3 source) {
assign(source);
}
*/
public PwEntryV3(PwGroupV3 p) {
this(p, true, true);
}
public PwEntryV3(PwGroupV3 p, boolean initId, boolean initDates) {
parent = p;
groupId = ((PwGroupIdV3)parent.getId()).getId();
if (initId) {
Random random = new Random();
uuid = new byte[16];
random.nextBytes(uuid);
}
if (initDates) {
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
tCreation = new PwDate(now);
tLastAccess = new PwDate(now);
tLastMod = new PwDate(now);
tExpire = new PwDate(NEVER_EXPIRE);
}
}
/**
* @return the actual password byte array.
*/
@Override
public String getPassword(boolean decodeRef, PwDatabase db) {
if (password == null) {
return "";
}
return new String(password);
}
public byte[] getPasswordBytes() {
return password;
}
/**
* fill byte array
*/
private static void fill(byte[] array, byte value)
{
for (int i=0; i<array.length; i++)
array[i] = value;
return;
}
/** Securely erase old password before copying new. */
public void setPassword( byte[] buf, int offset, int len ) {
if( password != null ) {
fill( password, (byte)0 );
password = null;
}
password = new byte[len];
System.arraycopy( buf, offset, password, 0, len );
}
@Override
public void setPassword(String pass, PwDatabase db) {
byte[] password;
try {
password = pass.getBytes("UTF-8");
setPassword(password, 0, password.length);
} catch (UnsupportedEncodingException e) {
assert false;
password = pass.getBytes();
setPassword(password, 0, password.length);
}
}
/**
* @return the actual binaryData byte array.
*/
public byte[] getBinaryData() {
return binaryData;
}
/** Securely erase old data before copying new. */
public void setBinaryData( byte[] buf, int offset, int len ) {
if( binaryData != null ) {
fill( binaryData, (byte)0 );
binaryData = null;
}
binaryData = new byte[len];
System.arraycopy( buf, offset, binaryData, 0, len );
}
// Determine if this is a MetaStream entry
@Override
public boolean isMetaStream() {
if ( binaryData == null ) return false;
if ( additional == null || additional.length() == 0 ) return false;
if ( ! binaryDesc.equals(PMS_ID_BINDESC) ) return false;
if ( title == null ) return false;
if ( ! title.equals(PMS_ID_TITLE) ) return false;
if ( username == null ) return false;
if ( ! username.equals(PMS_ID_USER) ) return false;
if ( url == null ) return false;
if ( ! url.equals(PMS_ID_URL)) return false;
if ( !icon.isMetaStreamIcon() ) return false;
return true;
}
@Override
public void assign(PwEntry source) {
if ( ! (source instanceof PwEntryV3) ) {
throw new RuntimeException("DB version mix");
}
super.assign(source);
PwEntryV3 src = (PwEntryV3) source;
assign(src);
}
private void assign(PwEntryV3 source) {
title = source.title;
url = source.url;
groupId = source.groupId;
username = source.username;
additional = source.additional;
uuid = source.uuid;
int passLen = source.password.length;
password = new byte[passLen];
System.arraycopy(source.password, 0, password, 0, passLen);
tCreation = (PwDate) source.tCreation.clone();
tLastMod = (PwDate) source.tLastMod.clone();
tLastAccess = (PwDate) source.tLastAccess.clone();
tExpire = (PwDate) source.tExpire.clone();
binaryDesc = source.binaryDesc;
if ( source.binaryData != null ) {
int descLen = source.binaryData.length;
binaryData = new byte[descLen];
System.arraycopy(source.binaryData, 0, binaryData, 0, descLen);
}
parent = source.parent;
}
@Override
public Object clone() {
PwEntryV3 newEntry = (PwEntryV3) super.clone();
if (password != null) {
int passLen = password.length;
password = new byte[passLen];
System.arraycopy(password, 0, newEntry.password, 0, passLen);
}
newEntry.tCreation = (PwDate) tCreation.clone();
newEntry.tLastMod = (PwDate) tLastMod.clone();
newEntry.tLastAccess = (PwDate) tLastAccess.clone();
newEntry.tExpire = (PwDate) tExpire.clone();
newEntry.binaryDesc = binaryDesc;
if ( binaryData != null ) {
int descLen = binaryData.length;
newEntry.binaryData = new byte[descLen];
System.arraycopy(binaryData, 0, newEntry.binaryData, 0, descLen);
}
newEntry.parent = parent;
return newEntry;
}
@Override
public Date getLastAccessTime() {
return tLastAccess.getJDate();
}
@Override
public Date getCreationTime() {
return tCreation.getJDate();
}
@Override
public Date getExpiryTime() {
return tExpire.getJDate();
}
@Override
public Date getLastModificationTime() {
return tLastMod.getJDate();
}
@Override
public void setCreationTime(Date create) {
tCreation = new PwDate(create);
}
@Override
public void setLastModificationTime(Date mod) {
tLastMod = new PwDate(mod);
}
@Override
public void setLastAccessTime(Date access) {
tLastAccess = new PwDate(access);
}
@Override
public void setExpires(boolean expires) {
if (!expires) {
tExpire = PW_NEVER_EXPIRE;
}
}
@Override
public void setExpiryTime(Date expires) {
tExpire = new PwDate(expires);
}
@Override
public PwGroupV3 getParent() {
return parent;
}
@Override
public UUID getUUID() {
return Types.bytestoUUID(uuid);
}
@Override
public void setUUID(UUID u) {
uuid = Types.UUIDtoBytes(u);
}
@Override
public String getUsername(boolean decodeRef, PwDatabase db) {
if (username == null) {
return "";
}
return username;
}
@Override
public void setUsername(String user, PwDatabase db) {
username = user;
}
@Override
public String getTitle(boolean decodeRef, PwDatabase db) {
return title;
}
@Override
public void setTitle(String title, PwDatabase db) {
this.title = title;
}
@Override
public String getNotes(boolean decodeRef, PwDatabase db) {
return additional;
}
@Override
public void setNotes(String notes, PwDatabase db) {
additional = notes;
}
@Override
public String getUrl(boolean decodeRef, PwDatabase db) {
return url;
}
@Override
public void setUrl(String url, PwDatabase db) {
this.url = url;
}
@Override
public boolean expires() {
return ! IsNever(tExpire.getJDate());
}
public void populateBlankFields(PwDatabaseV3 db) {
if (icon == null) {
icon = db.iconFactory.getIcon(1);
}
if (username == null) {
username = "";
}
if (password == null) {
password = new byte[0];
}
if (uuid == null) {
uuid = Types.UUIDtoBytes(UUID.randomUUID());
}
if (title == null) {
title = "";
}
if (url == null) {
url = "";
}
if (additional == null) {
additional = "";
}
if (tCreation == null) {
tCreation = DEFAULT_PWDATE;
}
if (tLastMod == null) {
tLastMod = DEFAULT_PWDATE;
}
if (tLastAccess == null) {
tLastAccess = DEFAULT_PWDATE;
}
if (tExpire == null) {
tExpire = PW_NEVER_EXPIRE;
}
if (binaryDesc == null) {
binaryDesc = "";
}
if (binaryData == null) {
binaryData = new byte[0];
}
}
@Override
public void setParent(PwGroup parent) {
this.parent = (PwGroupV3) parent;
}
}

View File

@@ -1,547 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import com.keepassdroid.database.security.ProtectedBinary;
import com.keepassdroid.database.security.ProtectedString;
import com.keepassdroid.utils.SprEngine;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
public class PwEntryV4 extends PwEntry implements ITimeLogger {
public static final String STR_TITLE = "Title";
public static final String STR_USERNAME = "UserName";
public static final String STR_PASSWORD = "Password";
public static final String STR_URL = "URL";
public static final String STR_NOTES = "Notes";
public PwGroupV4 parent;
public UUID uuid = PwDatabaseV4.UUID_ZERO;
private HashMap<String, ProtectedString> fields = new HashMap<>();
public HashMap<String, ProtectedBinary> binaries = new HashMap<>();
public PwIconCustom customIcon = PwIconCustom.ZERO;
public String foregroundColor = "";
public String backgroupColor = "";
public String overrideURL = "";
public AutoType autoType = new AutoType();
public ArrayList<PwEntryV4> history = new ArrayList<>();
private Date parentGroupLastMod = PwDatabaseV4.DEFAULT_NOW;
private Date creation = PwDatabaseV4.DEFAULT_NOW;
private Date lastMod = PwDatabaseV4.DEFAULT_NOW;
private Date lastAccess = PwDatabaseV4.DEFAULT_NOW;
private Date expireDate = PwDatabaseV4.DEFAULT_NOW;
private boolean expires = false;
private long usageCount = 0;
public String url = "";
public String additional = "";
public String tags = "";
public Map<String, String> customData = new HashMap<String, String>();
public class AutoType implements Cloneable, Serializable {
private static final long OBF_OPT_NONE = 0;
public boolean enabled = true;
public long obfuscationOptions = OBF_OPT_NONE;
public String defaultSequence = "";
private HashMap<String, String> windowSeqPairs = new HashMap<String, String>();
@SuppressWarnings("unchecked")
public Object clone() {
AutoType auto;
try {
auto = (AutoType) super.clone();
}
catch (CloneNotSupportedException e) {
assert(false);
throw new RuntimeException(e);
}
auto.windowSeqPairs = (HashMap<String, String>) windowSeqPairs.clone();
return auto;
}
public void put(String key, String value) {
windowSeqPairs.put(key, value);
}
public Set<Entry<String, String>> entrySet() {
return windowSeqPairs.entrySet();
}
}
public PwEntryV4() {
}
public PwEntryV4(PwGroupV4 p) {
this(p, true, true);
}
public PwEntryV4(PwGroupV4 p, boolean initId, boolean initDates) {
parent = p;
if (initId) {
uuid = UUID.randomUUID();
}
if (initDates) {
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
creation = now;
lastAccess = now;
lastMod = now;
expires = false;
}
}
@SuppressWarnings("unchecked")
@Override
public PwEntry clone(boolean deepStrings) {
PwEntryV4 entry = (PwEntryV4) super.clone(deepStrings);
if (deepStrings) {
entry.fields = (HashMap<String, ProtectedString>) fields.clone();
}
return entry;
}
@Override
public void assign(PwEntry source) {
if ( ! (source instanceof PwEntryV4) ) {
throw new RuntimeException("DB version mix.");
}
super.assign(source);
PwEntryV4 src = (PwEntryV4) source;
assign(src);
}
private void assign(PwEntryV4 source) {
parent = source.parent;
uuid = source.uuid;
fields = source.fields;
binaries = source.binaries;
customIcon = source.customIcon;
foregroundColor = source.foregroundColor;
backgroupColor = source.backgroupColor;
overrideURL = source.overrideURL;
autoType = source.autoType;
history = source.history;
parentGroupLastMod = source.parentGroupLastMod;
creation = source.creation;
lastMod = source.lastMod;
lastAccess = source.lastAccess;
expireDate = source.expireDate;
expires = source.expires;
usageCount = source.usageCount;
url = source.url;
additional = source.additional;
}
@Override
public Object clone() {
PwEntryV4 newEntry = (PwEntryV4) super.clone();
return newEntry;
}
private String decodeRefKey(boolean decodeRef, String key, PwDatabase db) {
String text = getString(key);
if (decodeRef) {
text = decodeRef(text, db);
}
return text;
}
private String decodeRef(String text, PwDatabase db) {
if (db == null) { return text; }
SprEngine spr = SprEngine.getInstance(db);
return spr.compile(text, this, db);
}
@Override
public String getUsername(boolean decodeRef, PwDatabase db) {
return decodeRefKey(decodeRef, STR_USERNAME, db);
}
@Override
public String getTitle(boolean decodeRef, PwDatabase db) {
return decodeRefKey(decodeRef, STR_TITLE, db);
}
@Override
public String getPassword(boolean decodeRef, PwDatabase db) {
return decodeRefKey(decodeRef, STR_PASSWORD, db);
}
@Override
public Date getLastAccessTime() {
return lastAccess;
}
@Override
public Date getCreationTime() {
return creation;
}
@Override
public Date getExpiryTime() {
return expireDate;
}
@Override
public Date getLastModificationTime() {
return lastMod;
}
@Override
public void setTitle(String title, PwDatabase d) {
PwDatabaseV4 db = (PwDatabaseV4) d;
boolean protect = db.memoryProtection.protectTitle;
setString(STR_TITLE, title, protect);
}
@Override
public void setUsername(String user, PwDatabase d) {
PwDatabaseV4 db = (PwDatabaseV4) d;
boolean protect = db.memoryProtection.protectUserName;
setString(STR_USERNAME, user, protect);
}
@Override
public void setPassword(String pass, PwDatabase d) {
PwDatabaseV4 db = (PwDatabaseV4) d;
boolean protect = db.memoryProtection.protectPassword;
setString(STR_PASSWORD, pass, protect);
}
@Override
public void setUrl(String url, PwDatabase d) {
PwDatabaseV4 db = (PwDatabaseV4) d;
boolean protect = db.memoryProtection.protectUrl;
setString(STR_URL, url, protect);
}
@Override
public void setNotes(String notes, PwDatabase d) {
PwDatabaseV4 db = (PwDatabaseV4) d;
boolean protect = db.memoryProtection.protectNotes;
setString(STR_NOTES, notes, protect);
}
public void setCreationTime(Date date) {
creation = date;
}
public void setExpiryTime(Date date) {
expireDate = date;
}
public void setLastAccessTime(Date date) {
lastAccess = date;
}
public void setLastModificationTime(Date date) {
lastMod = date;
}
@Override
public PwGroupV4 getParent() {
return parent;
}
@Override
public UUID getUUID() {
return uuid;
}
@Override
public void setUUID(UUID u) {
uuid = u;
}
public String getString(String key) {
ProtectedString value = fields.get(key);
if ( value == null ) return new String("");
return value.toString();
}
public void setString(String key, String value, boolean protect) {
ProtectedString ps = new ProtectedString(protect, value);
fields.put(key, ps);
}
public Date getLocationChanged() {
return parentGroupLastMod;
}
public long getUsageCount() {
return usageCount;
}
public void setLocationChanged(Date date) {
parentGroupLastMod = date;
}
public void setUsageCount(long count) {
usageCount = count;
}
@Override
public boolean expires() {
return expires;
}
public void setExpires(boolean exp) {
expires = exp;
}
@Override
public String getNotes(boolean decodeRef, PwDatabase db) {
return decodeRefKey(decodeRef, STR_NOTES, db);
}
@Override
public String getUrl(boolean decodeRef, PwDatabase db) {
return decodeRefKey(decodeRef, STR_URL, db);
}
@Override
public PwIcon getIcon() {
if (customIcon == null || customIcon.uuid.equals(PwDatabaseV4.UUID_ZERO)) {
return super.getIcon();
} else {
return customIcon;
}
}
public void createBackup(PwDatabaseV4 db) {
PwEntryV4 copy = cloneDeep();
copy.history = new ArrayList<>();
history.add(copy);
if (db != null) maintainBackups(db);
}
@SuppressWarnings("unchecked")
public PwEntryV4 cloneDeep() {
PwEntryV4 entry = (PwEntryV4) clone(true);
entry.binaries = (HashMap<String, ProtectedBinary>) binaries.clone();
entry.history = (ArrayList<PwEntryV4>) history.clone();
entry.autoType = (AutoType) autoType.clone();
return entry;
}
private boolean maintainBackups(PwDatabaseV4 db) {
boolean deleted = false;
int maxItems = db.historyMaxItems;
if (maxItems >= 0) {
while (history.size() > maxItems) {
removeOldestBackup();
deleted = true;
}
}
long maxSize = db.historyMaxSize;
if (maxSize >= 0) {
while(true) {
long histSize = 0;
for (PwEntryV4 entry : history) {
histSize += entry.getSize();
}
if (histSize > maxSize) {
removeOldestBackup();
deleted = true;
} else {
break;
}
}
}
return deleted;
}
private void removeOldestBackup() {
Date min = null;
int index = -1;
for (int i = 0; i < history.size(); i++) {
PwEntry entry = history.get(i);
Date lastMod = entry.getLastModificationTime();
if ((min == null) || lastMod.before(min)) {
index = i;
min = lastMod;
}
}
if (index != -1) {
history.remove(index);
}
}
@Override
public boolean allowExtraFields() {
return true;
}
public Map<String, ProtectedString> getFields() {
return fields;
}
@Override
public Map<String, ProtectedString> getExtraProtectedFields() {
Map<String, ProtectedString> protectedFields = super.getExtraProtectedFields();
if (fields.size() > 0) {
for (Map.Entry<String, ProtectedString> pair : fields.entrySet()) {
String key = pair.getKey();
if (!PwEntryV4.IsStandardField(key)) {
protectedFields.put(key, pair.getValue());
}
}
}
return protectedFields;
}
@Override
public Map<String, String> getExtraFields(PwDatabase pm) {
Map<String, String> extraFields = super.getExtraFields(pm);
SprEngine spr = SprEngine.getInstance(pm);
// Display custom fields
if (fields.size() > 0) {
for (Map.Entry<String, ProtectedString> pair : fields.entrySet()) {
String key = pair.getKey();
// TODO Add hidden style for protection field
if (!PwEntryV4.IsStandardField(key)) {
extraFields.put(key, spr.compile(pair.getValue().toString(), this, pm));
}
}
}
return extraFields;
}
public static boolean IsStandardField(String key) {
return key.equals(STR_TITLE) || key.equals(STR_USERNAME)
|| key.equals(STR_PASSWORD) || key.equals(STR_URL)
|| key.equals(STR_NOTES);
}
public void addField(String label, ProtectedString value) {
fields.put(label, value);
}
@Override
public void removeExtraFields() {
Iterator<Entry<String, ProtectedString>> iter = fields.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, ProtectedString> pair = iter.next();
if (!PwEntryV4.IsStandardField(pair.getKey())) {
iter.remove();
}
}
}
private static final long FIXED_LENGTH_SIZE = 128; // Approximate fixed length size
public long getSize() {
long size = FIXED_LENGTH_SIZE;
for (Entry<String, ProtectedString> pair : fields.entrySet()) {
size += pair.getKey().length();
size += pair.getValue().length();
}
for (Entry<String, ProtectedBinary> pair : binaries.entrySet()) {
size += pair.getKey().length();
size += pair.getValue().length();
}
size += autoType.defaultSequence.length();
for (Entry<String, String> pair : autoType.entrySet()) {
size += pair.getKey().length();
size += pair.getValue().length();
}
for (PwEntryV4 entry : history) {
size += entry.getSize();
}
size += overrideURL.length();
size += tags.length();
return size;
}
@Override
public void touch(boolean modified, boolean touchParents) {
super.touch(modified, touchParents);
++usageCount;
}
@Override
public void touchLocation() {
parentGroupLastMod = new Date();
}
@Override
public void setParent(PwGroup parent) {
this.parent = (PwGroupV4) parent;
}
public boolean isSearchingEnabled() {
if (parent != null) {
return parent.isSearchEnabled();
}
return PwGroupV4.DEFAULT_SEARCHING_ENABLED;
}
}

View File

@@ -1,314 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import com.keepassdroid.utils.StrUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
public abstract class PwGroup extends PwNode {
// TODO Change dependency and make private
public List<PwGroup> childGroups = new ArrayList<>();
public List<PwEntry> childEntries = new ArrayList<>();
public String name = "";
public PwIconStandard icon;
private List<PwNode> children = new ArrayList<>();
public void initNewGroup(String nm, PwGroupId newId) {
setId(newId);
name = nm;
}
public void addChildGroup(PwGroup group) {
this.childGroups.add(group);
}
public void addChildEntry(PwEntry entry) {
this.childEntries.add(entry);
}
public void removeChildGroup(PwGroup group) {
this.childGroups.remove(group);
}
public void removeChildEntry(PwEntry entry) {
this.childEntries.remove(entry);
}
public int numbersOfChildGroups() {
return childGroups.size();
}
public int numbersOfChildEntries() {
return childEntries.size();
}
@Override
public Type getType() {
return Type.GROUP;
}
/**
* Filter MetaStream entries and return children
* @return List of direct children (one level below) as PwNode
*/
public List<PwNode> getDirectChildren() {
children.clear();
children.addAll(childGroups);
for(PwEntry child : childEntries) {
if (!child.isMetaStream())
children.add(child);
}
return children;
}
/**
* Number of direct elements in Node (one level below)
* @return Size of child elements, default is 0
*/
public int numberOfDirectChildren() {
return childGroups.size() + childEntries.size();
}
public boolean isContainedIn(PwGroup container) {
PwGroup cur = this;
while (cur != null) {
if (cur == container) {
return true;
}
cur = cur.getParent();
}
return false;
}
public abstract PwGroupId getId();
public abstract void setId(PwGroupId id);
@Override
public String getDisplayTitle() {
return getName();
}
public abstract String getName();
public abstract Date getLastMod();
public PwIcon getIcon() {
return icon;
}
public abstract void setLastAccessTime(Date date);
public abstract void setLastModificationTime(Date date);
public boolean allowAddEntryIfIsRoot() {
return false;
}
public void touch(boolean modified, boolean touchParents) {
Date now = new Date();
setLastAccessTime(now);
if (modified) {
setLastModificationTime(now);
}
PwGroup parent = getParent();
if (touchParents && parent != null) {
parent.touch(modified, true);
}
}
public void searchEntries(SearchParameters sp, List<PwEntry> listStorage) {
if (sp == null) { return; }
if (listStorage == null) { return; }
List<String> terms = StrUtil.splitSearchTerms(sp.searchString);
if (terms.size() <= 1 || sp.regularExpression) {
searchEntriesSingle(sp, listStorage);
return;
}
// Search longest term first
Comparator<String> stringLengthComparator = new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
return lhs.length() - rhs.length();
}
};
Collections.sort(terms, stringLengthComparator);
String fullSearch = sp.searchString;
List<PwEntry> pg = this.childEntries;
for (int i = 0; i < terms.size(); i ++) {
List<PwEntry> pgNew = new ArrayList<PwEntry>();
sp.searchString = terms.get(i);
boolean negate = false;
if (sp.searchString.startsWith("-")) {
sp.searchString.substring(1);
negate = sp.searchString.length() > 0;
}
if (!searchEntriesSingle(sp, pgNew)) {
pg = null;
break;
}
List<PwEntry> complement = new ArrayList<PwEntry>();
if (negate) {
for (PwEntry entry: pg) {
if (!pgNew.contains(entry)) {
complement.add(entry);
}
}
pg = complement;
}
else {
pg = pgNew;
}
}
if (pg != null) {
listStorage.addAll(pg);
}
sp.searchString = fullSearch;
}
private boolean searchEntriesSingle(SearchParameters spIn, List<PwEntry> listStorage) {
SearchParameters sp = (SearchParameters) spIn.clone();
EntryHandler<PwEntry> eh;
if (sp.searchString.length() <= 0) {
eh = new EntrySearchHandlerAll(sp, listStorage);
} else {
eh = EntrySearchHandler.getInstance(this, sp, listStorage);
}
if (!preOrderTraverseTree(null, eh)) { return false; }
return true;
}
public boolean preOrderTraverseTree(GroupHandler<PwGroup> groupHandler, EntryHandler<PwEntry> entryHandler) {
if (entryHandler != null) {
for (PwEntry entry : childEntries) {
if (!entryHandler.operate(entry)) return false;
}
}
for (PwGroup group : childGroups) {
if ((groupHandler != null) && !groupHandler.operate(group)) return false;
group.preOrderTraverseTree(groupHandler, entryHandler);
}
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PwGroup pwGroup = (PwGroup) o;
return isSameType(pwGroup)
&& (getId() != null ? getId().equals(pwGroup.getId()) : pwGroup.getId() == null);
}
@Override
public int hashCode() {
PwGroupId groupId = getId();
return groupId != null ? groupId.hashCode() : 0;
}
/**
* Group comparator by name
*/
public static class GroupNameComparator implements Comparator<PwGroup> {
private boolean ascending;
public GroupNameComparator() {
this(true);
}
public GroupNameComparator(boolean ascending) {
this.ascending = ascending;
}
public int compare(PwGroup object1, PwGroup object2) {
if (object1.equals(object2))
return 0;
int groupNameComp = object1.getName().compareToIgnoreCase(object2.getName());
// If same name, can be different
if (groupNameComp == 0) {
return object1.hashCode() - object2.hashCode();
}
// If descending
if (!ascending)
groupNameComp = -groupNameComp;
return groupNameComp;
}
}
/**
* Group comparator by name
*/
public static class GroupCreationComparator implements Comparator<PwGroup> {
private boolean ascending;
public GroupCreationComparator() {
this(true);
}
public GroupCreationComparator(boolean ascending) {
this.ascending = ascending;
}
public int compare(PwGroup object1, PwGroup object2) {
if (object1.equals(object2))
return 0;
int groupCreationComp = object1.getCreationTime().compareTo(object2.getCreationTime());
// If same creation, can be different
if (groupCreationComp == 0) {
return object1.hashCode() - object2.hashCode();
}
// If descending
if (!ascending)
groupCreationComp = -groupCreationComp;
return groupCreationComp;
}
}
}

View File

@@ -1,7 +0,0 @@
package com.keepassdroid.database;
import java.io.Serializable;
public abstract class PwGroupId implements Serializable {
}

View File

@@ -1,32 +0,0 @@
package com.keepassdroid.database;
import java.util.UUID;
public class PwGroupIdV4 extends PwGroupId {
private UUID uuid;
public PwGroupIdV4(UUID u) {
uuid = u;
}
@Override
public boolean equals(Object id) {
if ( ! (id instanceof PwGroupIdV4) ) {
return false;
}
PwGroupIdV4 v4 = (PwGroupIdV4) id;
return uuid.equals(v4.uuid);
}
@Override
public int hashCode() {
return uuid.hashCode();
}
public UUID getId() {
return uuid;
}
}

View File

@@ -1,166 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
This file was derived from
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
This file was derived from
Java clone of KeePass - A KeePass file viewer for Java
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import android.content.Intent;
import android.os.Bundle;
import com.keepassdroid.utils.Types;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* @author Brian Pellin <bpellin@gmail.com>
* @author Naomaru Itoi <nao@phoneid.org>
* @author Bill Zwicky <wrzwicky@pobox.com>
* @author Dominik Reichl <dominik.reichl@t-online.de>
*/
public class PwGroupV3 extends PwGroup {
public String toString() {
return name;
}
public static final Date NEVER_EXPIRE = PwEntryV3.NEVER_EXPIRE;
/** Size of byte buffer needed to hold this struct. */
public static final int BUF_SIZE = 124;
// for tree traversing
public PwGroupV3 parent = null;
public int groupId;
public PwDate tCreation;
public PwDate tLastMod;
public PwDate tLastAccess;
public PwDate tExpire;
public int level; // short
/** Used by KeePass internally, don't use */
public int flags;
public void setGroups(List<PwGroup> groups) {
childGroups = groups;
}
@Override
public PwGroup getParent() {
return parent;
}
@Override
public PwGroupId getId() {
return new PwGroupIdV3(groupId);
}
@Override
public void setId(PwGroupId id) {
PwGroupIdV3 id3 = (PwGroupIdV3) id;
groupId = id3.getId();
}
@Override
public String getName() {
return name;
}
@Override
public Date getLastMod() {
return tLastMod.getJDate();
}
@Override
public void setParent(PwGroup prt) {
parent = (PwGroupV3) prt;
level = parent.level + 1;
}
@Override
public void initNewGroup(String nm, PwGroupId newId) {
super.initNewGroup(nm, newId);
Date now = Calendar.getInstance().getTime();
tCreation = new PwDate(now);
tLastAccess = new PwDate(now);
tLastMod = new PwDate(now);
tExpire = new PwDate(PwGroupV3.NEVER_EXPIRE);
}
public void populateBlankFields(PwDatabaseV3 db) {
if (icon == null) {
icon = db.iconFactory.getIcon(1);
}
if (name == null) {
name = "";
}
if (tCreation == null) {
tCreation = PwEntryV3.DEFAULT_PWDATE;
}
if (tLastMod == null) {
tLastMod = PwEntryV3.DEFAULT_PWDATE;
}
if (tLastAccess == null) {
tLastAccess = PwEntryV3.DEFAULT_PWDATE;
}
if (tExpire == null) {
tExpire = PwEntryV3.DEFAULT_PWDATE;
}
}
@Override
public void setLastAccessTime(Date date) {
tLastAccess = new PwDate(date);
}
@Override
public void setLastModificationTime(Date date) {
tLastMod = new PwDate(date);
}
@Override
public Date getCreationTime() {
if(tCreation != null)
return tCreation.getJDate();
else
return new Date();
}
}

View File

@@ -1,242 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class PwGroupV4 extends PwGroup implements ITimeLogger {
//public static final int FOLDER_ICON = 48;
public static final boolean DEFAULT_SEARCHING_ENABLED = true;
public PwGroupV4 parent = null;
public UUID uuid = PwDatabaseV4.UUID_ZERO;
public String notes = "";
public PwIconCustom customIcon = PwIconCustom.ZERO;
public boolean isExpanded = true;
public String defaultAutoTypeSequence = "";
public Boolean enableAutoType = null;
public Boolean enableSearching = null;
public UUID lastTopVisibleEntry = PwDatabaseV4.UUID_ZERO;
private Date parentGroupLastMod = PwDatabaseV4.DEFAULT_NOW;
private Date creation = PwDatabaseV4.DEFAULT_NOW;
private Date lastMod = PwDatabaseV4.DEFAULT_NOW;
private Date lastAccess = PwDatabaseV4.DEFAULT_NOW;
private Date expireDate = PwDatabaseV4.DEFAULT_NOW;
private boolean expires = false;
private long usageCount = 0;
public Map<String, String> customData = new HashMap<String, String>();
public PwGroupV4() {}
public PwGroupV4(boolean createUUID, boolean setTimes, String name, PwIconStandard icon) {
if (createUUID) {
uuid = UUID.randomUUID();
}
if (setTimes) {
creation = lastMod = lastAccess = new Date();
}
this.name = name;
this.icon = icon;
}
@Override
public void initNewGroup(String nm, PwGroupId newId) {
super.initNewGroup(nm, newId);
lastAccess = lastMod = creation = parentGroupLastMod = new Date();
}
public void AddGroup(PwGroupV4 subGroup, boolean takeOwnership) {
AddGroup(subGroup, takeOwnership, false);
}
public void AddGroup(PwGroupV4 subGroup, boolean takeOwnership, boolean updateLocationChanged) {
if ( subGroup == null ) throw new RuntimeException("subGroup");
childGroups.add(subGroup);
if ( takeOwnership ) subGroup.parent = this;
if ( updateLocationChanged ) subGroup.parentGroupLastMod = new Date(System.currentTimeMillis());
}
public void AddEntry(PwEntryV4 pe, boolean takeOwnership) {
AddEntry(pe, takeOwnership, false);
}
public void AddEntry(PwEntryV4 pe, boolean takeOwnership, boolean updateLocationChanged) {
assert(pe != null);
addChildEntry(pe);
if ( takeOwnership ) pe.parent = this;
if ( updateLocationChanged ) pe.setLocationChanged(new Date(System.currentTimeMillis()));
}
@Override
public PwGroup getParent() {
return parent;
}
public void buildChildGroupsRecursive(List<PwGroup> list) {
list.add(this);
for ( int i = 0; i < numbersOfChildGroups(); i++) {
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
child.buildChildGroupsRecursive(list);
}
}
public void buildChildEntriesRecursive(List<PwEntry> list) {
for ( int i = 0; i < numbersOfChildEntries(); i++ ) {
list.add(childEntries.get(i));
}
for ( int i = 0; i < numbersOfChildGroups(); i++ ) {
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
child.buildChildEntriesRecursive(list);
}
}
@Override
public PwGroupId getId() {
return new PwGroupIdV4(uuid);
}
@Override
public void setId(PwGroupId id) {
PwGroupIdV4 id4 = (PwGroupIdV4) id;
uuid = id4.getId();
}
@Override
public String getName() {
return name;
}
@Override
public Date getLastMod() {
return parentGroupLastMod;
}
public Date getCreationTime() {
return creation;
}
public Date getExpiryTime() {
return expireDate;
}
public Date getLastAccessTime() {
return lastAccess;
}
public Date getLastModificationTime() {
return lastMod;
}
public Date getLocationChanged() {
return parentGroupLastMod;
}
public long getUsageCount() {
return usageCount;
}
public void setCreationTime(Date date) {
creation = date;
}
public void setExpiryTime(Date date) {
expireDate = date;
}
@Override
public void setLastAccessTime(Date date) {
lastAccess = date;
}
@Override
public void setLastModificationTime(Date date) {
lastMod = date;
}
public void setLocationChanged(Date date) {
parentGroupLastMod = date;
}
public void setUsageCount(long count) {
usageCount = count;
}
public boolean expires() {
return expires;
}
public void setExpires(boolean exp) {
expires = exp;
}
@Override
public void setParent(PwGroup prt) {
parent = (PwGroupV4) prt;
}
@Override
public boolean allowAddEntryIfIsRoot() {
return true;
}
@Override
public PwIcon getIcon() {
if (customIcon == null || customIcon.uuid.equals(PwDatabaseV4.UUID_ZERO)) {
return super.getIcon();
} else {
return customIcon;
}
}
public boolean isSearchEnabled() {
PwGroupV4 group = this;
while (group != null) {
Boolean search = group.enableSearching;
if (search != null) {
return search;
}
group = group.parent;
}
// If we get to the root tree and its null, default to true
return true;
}
}

View File

@@ -1,14 +0,0 @@
package com.keepassdroid.database;
import java.io.Serializable;
public abstract class PwIcon implements Serializable {
public boolean isMetaStreamIcon() {
return false;
}
public void writeBytes() {
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
package com.keepassdroid.database;
import java.io.Serializable;
import java.util.Date;
/**
* Abstract class who manage Groups and Entries
*/
public abstract class PwNode implements Serializable {
/**
* Type of available Nodes
*/
public enum Type {
GROUP, ENTRY
}
/**
* @return Type of Node
*/
public abstract Type getType();
/**
* @return Title to display as view
*/
public abstract String getDisplayTitle();
/**
* @return Visual icon
*/
public abstract PwIcon getIcon();
/**
* @return Creation date and time of the node
*/
public abstract Date getCreationTime();
/**
* Retrieve the parent node
* @return PwGroup parent as group
*/
public abstract PwGroup getParent();
/**
* Assign a parent to this node
*/
public abstract void setParent(PwGroup parent);
/**
* If the content (type, title, icon) is visually the same
* @param o Node to compare
* @return True if visually as o
*/
public boolean isContentVisuallyTheSame(PwNode o) {
return getType().equals(o.getType())
&& getDisplayTitle().equals(o.getDisplayTitle())
&& getIcon().equals(o.getIcon());
}
/**
* Define if it's the same type of another node
* @param otherNode The other node to test
* @return true if both have the same type
*/
boolean isSameType(PwNode otherNode) {
return getType() != null ? getType().equals(otherNode.getType()) : otherNode.getType() == null;
}
}

View File

@@ -1,5 +0,0 @@
package com.keepassdroid.database;
public enum PwVersion {
V3, V4
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
public class SearchParametersFactory {
public static SearchParameters getNone(PwDatabase db) {
SearchParameters sp = getInstance(db);
sp.setupNone();
return sp;
}
public static SearchParameters getInstance(PwDatabase db) {
if (db instanceof PwDatabase) {
return new SearchParametersV4();
}
else {
return new SearchParameters();
}
}
public static SearchParameters getInstance(PwGroup group) {
if (group instanceof PwGroupV4) {
return new SearchParametersV4();
}
else {
return new SearchParameters();
}
}
}

View File

@@ -1,176 +0,0 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import java.util.Comparator;
public enum SortNodeEnum {
DB, TITLE, USERNAME, CREATION_TIME, LAST_MODIFY_TIME, LAST_ACCESS_TIME;
public Comparator<PwNode> getNodeComparator(boolean ascending, boolean groupsBefore) {
switch (this) {
case DB:
return new NodeCreationComparator(ascending, groupsBefore); // TODO Sort
default:
case TITLE:
return new NodeTitleComparator(ascending, groupsBefore);
case USERNAME:
return new NodeCreationComparator(ascending, groupsBefore); // TODO Sort
case CREATION_TIME:
return new NodeCreationComparator(ascending, groupsBefore);
case LAST_MODIFY_TIME:
return new NodeCreationComparator(ascending, groupsBefore); // TODO Sort
case LAST_ACCESS_TIME:
return new NodeCreationComparator(ascending, groupsBefore); // TODO Sort
}
}
private static abstract class NodeComparator implements Comparator<PwNode> {
boolean ascending;
boolean groupsBefore;
NodeComparator() {
this(true, true);
}
NodeComparator(boolean groupsBefore) {
this(true, groupsBefore);
}
NodeComparator(boolean ascending, boolean groupsBefore) {
this.ascending = ascending;
this.groupsBefore = groupsBefore;
}
}
/**
* Comparator of Node by Title, Groups first, Entries second
*/
public static class NodeTitleComparator extends NodeComparator {
public NodeTitleComparator() {
super();
}
public NodeTitleComparator(boolean groupsBefore) {
super(groupsBefore);
}
public NodeTitleComparator(boolean ascending, boolean groupsBefore) {
super(ascending, groupsBefore);
}
public int compare(PwNode object1, PwNode object2) {
if (object1.equals(object2))
return 0;
if (object1 instanceof PwGroup) {
if (object2 instanceof PwGroup) {
return new PwGroup.GroupNameComparator(ascending)
.compare((PwGroup) object1, (PwGroup) object2);
} else if (object2 instanceof PwEntry) {
if(groupsBefore)
return -1;
else
return 1;
} else {
return -1;
}
} else if (object1 instanceof PwEntry) {
if(object2 instanceof PwEntry) {
return new PwEntry.EntryNameComparator(ascending)
.compare((PwEntry) object1, (PwEntry) object2);
} else if (object2 instanceof PwGroup) {
if(groupsBefore)
return 1;
else
return -1;
} else {
return -1;
}
}
int nodeNameComp = object1.getDisplayTitle()
.compareToIgnoreCase(object2.getDisplayTitle());
// If same name, can be different
if (nodeNameComp == 0)
return object1.hashCode() - object2.hashCode();
return nodeNameComp;
}
}
/**
* Comparator of node by creation, Groups first, Entries second
*/
public static class NodeCreationComparator extends NodeComparator {
public NodeCreationComparator() {
super();
}
public NodeCreationComparator(boolean groupsBefore) {
super(groupsBefore);
}
public NodeCreationComparator(boolean ascending, boolean groupsBefore) {
super(ascending, groupsBefore);
}
@Override
public int compare(PwNode object1, PwNode object2) {
if (object1.equals(object2))
return 0;
if (object1 instanceof PwGroup) {
if (object2 instanceof PwGroup) {
return new PwGroup.GroupCreationComparator(ascending)
.compare((PwGroup) object1, (PwGroup) object2);
} else if (object2 instanceof PwEntry) {
if(groupsBefore)
return -1;
else
return 1;
} else {
return -1;
}
} else if (object1 instanceof PwEntry) {
if(object2 instanceof PwEntry) {
return new PwEntry.EntryCreationComparator(ascending)
.compare((PwEntry) object1, (PwEntry) object2);
} else if (object2 instanceof PwGroup) {
if(groupsBefore)
return 1;
else
return -1;
} else {
return -1;
}
}
int nodeCreationComp = object1.getCreationTime()
.compareTo(object2.getCreationTime());
// If same creation, can be different
if (nodeCreationComp == 0) {
return object1.hashCode() - object2.hashCode();
}
return nodeCreationComp;
}
}
}

View File

@@ -1,13 +0,0 @@
package com.keepassdroid.database.edit;
import android.os.Handler;
import com.keepassdroid.database.PwNode;
public abstract class AfterAddNodeOnFinish extends OnFinish {
public AfterAddNodeOnFinish(Handler handler) {
super(handler);
}
public abstract void run(PwNode pwNode);
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database.load;
import com.keepassdroid.tasks.UpdateStatus;
import com.keepassdroid.database.PwDatabaseV4Debug;
import com.keepassdroid.database.exception.InvalidDBException;
import java.io.IOException;
import java.io.InputStream;
public class ImporterV4Debug extends ImporterV4 {
@Override
protected PwDatabaseV4Debug createDB() {
return new PwDatabaseV4Debug();
}
@Override
public PwDatabaseV4Debug openDatabase(InputStream inStream, String password,
InputStream keyInputFile, UpdateStatus status, long roundsFix) throws IOException,
InvalidDBException {
return (PwDatabaseV4Debug) super.openDatabase(inStream, password, keyInputFile, status,
roundsFix);
}
}

View File

@@ -1,840 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database.save;
import android.util.Xml;
import com.keepassdroid.crypto.CipherFactory;
import com.keepassdroid.crypto.PwStreamCipherFactory;
import com.keepassdroid.crypto.engine.CipherEngine;
import com.keepassdroid.crypto.keyDerivation.KdfEngine;
import com.keepassdroid.crypto.keyDerivation.KdfFactory;
import com.keepassdroid.database.CrsAlgorithm;
import com.keepassdroid.database.EntryHandler;
import com.keepassdroid.database.GroupHandler;
import com.keepassdroid.database.ITimeLogger;
import com.keepassdroid.database.PwCompressionAlgorithm;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.PwDatabaseV4.MemoryProtectionConfig;
import com.keepassdroid.database.PwDatabaseV4XML;
import com.keepassdroid.database.PwDbHeader;
import com.keepassdroid.database.PwDbHeaderV4;
import com.keepassdroid.database.PwDefsV4;
import com.keepassdroid.database.PwDeletedObject;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV4;
import com.keepassdroid.database.PwEntryV4.AutoType;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV4;
import com.keepassdroid.database.PwIconCustom;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.security.ProtectedBinary;
import com.keepassdroid.database.security.ProtectedString;
import com.keepassdroid.stream.HashedBlockOutputStream;
import com.keepassdroid.stream.HmacBlockOutputStream;
import com.keepassdroid.stream.LEDataOutputStream;
import com.keepassdroid.utils.DateUtil;
import com.keepassdroid.utils.EmptyUtils;
import com.keepassdroid.utils.MemUtil;
import com.keepassdroid.utils.Types;
import org.joda.time.DateTime;
import org.spongycastle.crypto.StreamCipher;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import biz.source_code.base64Coder.Base64Coder;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrCompressed;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrId;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrProtected;
import static com.keepassdroid.database.PwDatabaseV4XML.AttrRef;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoType;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeDefaultSeq;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeEnabled;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemAutoTypeObfuscation;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBgColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBinaries;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemBinary;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCreationTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomData;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconID;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItemData;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIconItemID;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemCustomIcons;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDefaultUser;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDefaultUserChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDesc;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbDescChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChangeForce;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChangeRec;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbKeyChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbMntncHistoryDays;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDbNameChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletedObject;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletedObjects;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDeletionTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemDocNode;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEnableAutoType;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEnableSearching;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntry;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntryTemplatesGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemEntryTemplatesGroupChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemExpires;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemExpiryTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemFgColor;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGenerator;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemGroupDefaultAutoTypeSeq;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHeaderHash;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistory;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistoryMaxItems;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemHistoryMaxSize;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemIcon;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemIsExpanded;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemKey;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemKeystrokeSequence;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastAccessTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastModTime;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastSelectedGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastTopVisibleEntry;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLastTopVisibleGroup;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemLocationChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemMemoryProt;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemMeta;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemNotes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemOverrideUrl;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtNotes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtPassword;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtTitle;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtURL;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemProtUserName;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinChanged;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinEnabled;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRecycleBinUuid;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemRoot;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemString;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemStringDictExItem;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemTags;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemTimes;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemUsageCount;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemUuid;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemValue;
import static com.keepassdroid.database.PwDatabaseV4XML.ElemWindow;
import static com.keepassdroid.database.PwDatabaseV4XML.ValFalse;
import static com.keepassdroid.database.PwDatabaseV4XML.ValTrue;
public class PwDbV4Output extends PwDbOutput {
PwDatabaseV4 mPM;
private StreamCipher randomStream;
private XmlSerializer xml;
private PwDbHeaderV4 header;
private byte[] hashOfHeader;
private byte[] headerHmac;
private CipherEngine engine = null;
protected PwDbV4Output(PwDatabaseV4 pm, OutputStream os) {
super(os);
mPM = pm;
}
@Override
public void output() throws PwDbOutputException {
try {
try {
engine = CipherFactory.getInstance(mPM.dataCipher);
} catch (NoSuchAlgorithmException e) {
throw new PwDbOutputException("No such cipher", e);
}
header = (PwDbHeaderV4) outputHeader(mOS);
OutputStream osPlain;
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {
CipherOutputStream cos = attachStreamEncryptor(header, mOS);
cos.write(header.streamStartBytes);
HashedBlockOutputStream hashed = new HashedBlockOutputStream(cos);
osPlain = hashed;
} else {
mOS.write(hashOfHeader);
mOS.write(headerHmac);
HmacBlockOutputStream hbos = new HmacBlockOutputStream(mOS, mPM.hmacKey);
osPlain = attachStreamEncryptor(header, hbos);
}
OutputStream osXml;
try {
if (mPM.compressionAlgorithm == PwCompressionAlgorithm.Gzip) {
osXml = new GZIPOutputStream(osPlain);
} else {
osXml = osPlain;
}
if (header.version >= PwDbHeaderV4.FILE_VERSION_32_4) {
PwDbInnerHeaderOutputV4 ihOut = new PwDbInnerHeaderOutputV4((PwDatabaseV4)mPM, header, osXml);
ihOut.output();
}
outputDatabase(osXml);
osXml.close();
} catch (IllegalArgumentException e) {
throw new PwDbOutputException(e);
} catch (IllegalStateException e) {
throw new PwDbOutputException(e);
}
} catch (IOException e) {
throw new PwDbOutputException(e);
}
}
private class GroupWriter extends GroupHandler<PwGroup> {
private Stack<PwGroupV4> groupStack;
public GroupWriter(Stack<PwGroupV4> gs) {
groupStack = gs;
}
@Override
public boolean operate(PwGroup g) {
PwGroupV4 group = (PwGroupV4) g;
assert(group != null);
while(true) {
try {
if (group.parent == groupStack.peek()) {
groupStack.push(group);
startGroup(group);
break;
} else {
groupStack.pop();
if (groupStack.size() <= 0) return false;
endGroup();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return true;
}
}
private class EntryWriter extends EntryHandler<PwEntry> {
@Override
public boolean operate(PwEntry e) {
PwEntryV4 entry = (PwEntryV4) e;
assert(entry != null);
try {
writeEntry(entry, false);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return true;
}
}
private void outputDatabase(OutputStream os) throws IllegalArgumentException, IllegalStateException, IOException {
xml = Xml.newSerializer();
xml.setOutput(os, "UTF-8");
xml.startDocument("UTF-8", true);
xml.startTag(null, ElemDocNode);
writeMeta();
PwGroupV4 root = (PwGroupV4) mPM.rootGroup;
xml.startTag(null, ElemRoot);
startGroup(root);
Stack<PwGroupV4> groupStack = new Stack<PwGroupV4>();
groupStack.push(root);
if (!root.preOrderTraverseTree(new GroupWriter(groupStack), new EntryWriter())) throw new RuntimeException("Writing groups failed");
while (groupStack.size() > 1) {
xml.endTag(null, ElemGroup);
groupStack.pop();
}
endGroup();
writeList(ElemDeletedObjects, mPM.deletedObjects);
xml.endTag(null, ElemRoot);
xml.endTag(null, ElemDocNode);
xml.endDocument();
}
private void writeMeta() throws IllegalArgumentException, IllegalStateException, IOException {
xml.startTag(null, ElemMeta);
writeObject(ElemGenerator, mPM.localizedAppName);
if (hashOfHeader != null) {
writeObject(ElemHeaderHash, String.valueOf(Base64Coder.encode(hashOfHeader)));
}
writeObject(ElemDbName, mPM.name, true);
writeObject(ElemDbNameChanged, mPM.nameChanged);
writeObject(ElemDbDesc, mPM.description, true);
writeObject(ElemDbDescChanged, mPM.descriptionChanged);
writeObject(ElemDbDefaultUser, mPM.defaultUserName, true);
writeObject(ElemDbDefaultUserChanged, mPM.defaultUserNameChanged);
writeObject(ElemDbMntncHistoryDays, mPM.maintenanceHistoryDays);
writeObject(ElemDbColor, mPM.color);
writeObject(ElemDbKeyChanged, mPM.keyLastChanged);
writeObject(ElemDbKeyChangeRec, mPM.keyChangeRecDays);
writeObject(ElemDbKeyChangeForce, mPM.keyChangeForceDays);
writeList(ElemMemoryProt, mPM.memoryProtection);
writeCustomIconList();
writeObject(ElemRecycleBinEnabled, mPM.recycleBinEnabled);
writeObject(ElemRecycleBinUuid, mPM.recycleBinUUID);
writeObject(ElemRecycleBinChanged, mPM.recycleBinChanged);
writeObject(ElemEntryTemplatesGroup, mPM.entryTemplatesGroup);
writeObject(ElemEntryTemplatesGroupChanged, mPM.entryTemplatesGroupChanged);
writeObject(ElemHistoryMaxItems, mPM.historyMaxItems);
writeObject(ElemHistoryMaxSize, mPM.historyMaxSize);
writeObject(ElemLastSelectedGroup, mPM.lastSelectedGroup);
writeObject(ElemLastTopVisibleGroup, mPM.lastTopVisibleGroup);
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {
writeBinPool();
}
writeList(ElemCustomData, mPM.customData);
xml.endTag(null, ElemMeta);
}
private CipherOutputStream attachStreamEncryptor(PwDbHeaderV4 header, OutputStream os) throws PwDbOutputException {
Cipher cipher;
try {
//mPM.makeFinalKey(header.masterSeed, mPM.kdfParameters);
cipher = engine.getCipher(Cipher.ENCRYPT_MODE, mPM.finalKey, header.encryptionIV);
} catch (Exception e) {
throw new PwDbOutputException("Invalid algorithm.", e);
}
CipherOutputStream cos = new CipherOutputStream(os, cipher);
return cos;
}
@Override
protected SecureRandom setIVs(PwDbHeader header) throws PwDbOutputException {
SecureRandom random = super.setIVs(header);
PwDbHeaderV4 h = (PwDbHeaderV4) header;
random.nextBytes(h.masterSeed);
int ivLength = engine.ivLength();
if (ivLength != h.encryptionIV.length) {
h.encryptionIV = new byte[ivLength];
}
random.nextBytes(h.encryptionIV);
UUID kdfUUID = mPM.kdfParameters.kdfUUID;
KdfEngine kdf = KdfFactory.get(kdfUUID);
kdf.randomize(mPM.kdfParameters);
if (h.version < PwDbHeaderV4.FILE_VERSION_32_4) {
h.innerRandomStream = CrsAlgorithm.Salsa20;
h.innerRandomStreamKey = new byte[32];
} else {
h.innerRandomStream = CrsAlgorithm.ChaCha20;
h.innerRandomStreamKey = new byte[64];
}
random.nextBytes(h.innerRandomStreamKey);
randomStream = PwStreamCipherFactory.getInstance(h.innerRandomStream, h.innerRandomStreamKey);
if (randomStream == null) {
throw new PwDbOutputException("Invalid random cipher");
}
if ( h.version < PwDbHeaderV4.FILE_VERSION_32_4) {
random.nextBytes(h.streamStartBytes);
}
return random;
}
@Override
public PwDbHeader outputHeader(OutputStream os) throws PwDbOutputException {
PwDbHeaderV4 header = new PwDbHeaderV4(mPM);
setIVs(header);
PwDbHeaderOutputV4 pho = new PwDbHeaderOutputV4(mPM, header, os);
try {
pho.output();
} catch (IOException e) {
throw new PwDbOutputException("Failed to output the header.", e);
}
hashOfHeader = pho.getHashOfHeader();
headerHmac = pho.headerHmac;
return header;
}
private void startGroup(PwGroupV4 group) throws IllegalArgumentException, IllegalStateException, IOException {
xml.startTag(null, ElemGroup);
writeObject(ElemUuid, group.uuid);
writeObject(ElemName, group.name);
writeObject(ElemNotes, group.notes);
writeObject(ElemIcon, group.icon.iconId);
if (!group.customIcon.equals(PwIconCustom.ZERO)) {
writeObject(ElemCustomIconID, group.customIcon.uuid);
}
writeList(ElemTimes, group);
writeObject(ElemIsExpanded, group.isExpanded);
writeObject(ElemGroupDefaultAutoTypeSeq, group.defaultAutoTypeSequence);
writeObject(ElemEnableAutoType, group.enableAutoType);
writeObject(ElemEnableSearching, group.enableSearching);
writeObject(ElemLastTopVisibleEntry, group.lastTopVisibleEntry);
}
private void endGroup() throws IllegalArgumentException, IllegalStateException, IOException {
xml.endTag(null, ElemGroup);
}
private void writeEntry(PwEntryV4 entry, boolean isHistory) throws IllegalArgumentException, IllegalStateException, IOException {
assert(entry != null);
xml.startTag(null, ElemEntry);
writeObject(ElemUuid, entry.uuid);
writeObject(ElemIcon, entry.icon.iconId);
if (!entry.customIcon.equals(PwIconCustom.ZERO)) {
writeObject(ElemCustomIconID, entry.customIcon.uuid);
}
writeObject(ElemFgColor, entry.foregroundColor);
writeObject(ElemBgColor, entry.backgroupColor);
writeObject(ElemOverrideUrl, entry.overrideURL);
writeObject(ElemTags, entry.tags);
writeList(ElemTimes, entry);
writeList(entry.getFields(), true);
writeList(entry.binaries);
writeList(ElemAutoType, entry.autoType);
if (!isHistory) {
writeList(ElemHistory, entry.history, true);
} else {
assert(entry.history.size() == 0);
}
xml.endTag(null, ElemEntry);
}
private void writeObject(String key, ProtectedBinary value, boolean allowRef) throws IllegalArgumentException, IllegalStateException, IOException {
assert(key != null && value != null);
xml.startTag(null, ElemBinary);
xml.startTag(null, ElemKey);
xml.text(safeXmlString(key));
xml.endTag(null, ElemKey);
xml.startTag(null, ElemValue);
String strRef = null;
if (allowRef) {
int ref = mPM.binPool.poolFind(value);
strRef = Integer.toString(ref);
}
if (strRef != null) {
xml.attribute(null, AttrRef, strRef);
}
else {
subWriteValue(value);
}
xml.endTag(null, ElemValue);
xml.endTag(null, ElemBinary);
}
private void subWriteValue(ProtectedBinary value) throws IllegalArgumentException, IllegalStateException, IOException {
if (value.isProtected()) {
xml.attribute(null, AttrProtected, ValTrue);
int valLength = value.length();
if (valLength > 0) {
byte[] encoded = new byte[valLength];
randomStream.processBytes(value.getData(), 0, valLength, encoded, 0);
xml.text(String.valueOf(Base64Coder.encode(encoded)));
}
} else {
if (mPM.compressionAlgorithm == PwCompressionAlgorithm.Gzip) {
xml.attribute(null, AttrCompressed, ValTrue);
byte[] raw = value.getData();
byte[] compressed = MemUtil.compress(raw);
xml.text(String.valueOf(Base64Coder.encode(compressed)));
} else {
byte[] raw = value.getData();
xml.text(String.valueOf(Base64Coder.encode(raw)));
}
}
}
private void writeObject(String name, String value, boolean filterXmlChars) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && value != null);
xml.startTag(null, name);
if (filterXmlChars) {
value = safeXmlString(value);
}
xml.text(value);
xml.endTag(null, name);
}
private void writeObject(String name, String value) throws IllegalArgumentException, IllegalStateException, IOException {
writeObject(name, value, false);
}
private void writeObject(String name, Date value) throws IllegalArgumentException, IllegalStateException, IOException {
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {
writeObject(name, PwDatabaseV4XML.dateFormatter.get().format(value));
} else {
DateTime dt = new DateTime(value);
long seconds = DateUtil.convertDateToKDBX4Time(dt);
byte[] buf = LEDataOutputStream.writeLongBuf(seconds);
String b64 = new String(Base64Coder.encode(buf));
writeObject(name, b64);
}
}
private void writeObject(String name, long value) throws IllegalArgumentException, IllegalStateException, IOException {
writeObject(name, String.valueOf(value));
}
private void writeObject(String name, Boolean value) throws IllegalArgumentException, IllegalStateException, IOException {
String text;
if (value == null) {
text = "null";
}
else if (value) {
text = ValTrue;
}
else {
text = ValFalse;
}
writeObject(name, text);
}
private void writeObject(String name, UUID uuid) throws IllegalArgumentException, IllegalStateException, IOException {
byte[] data = Types.UUIDtoBytes(uuid);
writeObject(name, String.valueOf(Base64Coder.encode(data)));
}
private void writeObject(String name, String keyName, String keyValue, String valueName, String valueValue) throws IllegalArgumentException, IllegalStateException, IOException {
xml.startTag(null, name);
xml.startTag(null, keyName);
xml.text(safeXmlString(keyValue));
xml.endTag(null, keyName);
xml.startTag(null, valueName);
xml.text(safeXmlString(valueValue));
xml.endTag(null, valueName);
xml.endTag(null, name);
}
private void writeList(String name, AutoType autoType) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && autoType != null);
xml.startTag(null, name);
writeObject(ElemAutoTypeEnabled, autoType.enabled);
writeObject(ElemAutoTypeObfuscation, autoType.obfuscationOptions);
if (autoType.defaultSequence.length() > 0) {
writeObject(ElemAutoTypeDefaultSeq, autoType.defaultSequence, true);
}
for (Entry<String, String> pair : autoType.entrySet()) {
writeObject(ElemAutoTypeItem, ElemWindow, pair.getKey(), ElemKeystrokeSequence, pair.getValue());
}
xml.endTag(null, name);
}
private void writeList(Map<String, ProtectedString> strings, boolean isEntryString) throws IllegalArgumentException, IllegalStateException, IOException {
assert (strings != null);
for (Entry<String, ProtectedString> pair : strings.entrySet()) {
writeObject(pair.getKey(), pair.getValue(), isEntryString);
}
}
private void writeObject(String key, ProtectedString value, boolean isEntryString) throws IllegalArgumentException, IllegalStateException, IOException {
assert(key !=null && value != null);
xml.startTag(null, ElemString);
xml.startTag(null, ElemKey);
xml.text(safeXmlString(key));
xml.endTag(null, ElemKey);
xml.startTag(null, ElemValue);
boolean protect = value.isProtected();
if (isEntryString) {
if (key.equals(PwDefsV4.TITLE_FIELD)) {
protect = mPM.memoryProtection.protectTitle;
}
else if (key.equals(PwDefsV4.USERNAME_FIELD)) {
protect = mPM.memoryProtection.protectUserName;
}
else if (key.equals(PwDefsV4.PASSWORD_FIELD)) {
protect = mPM.memoryProtection.protectPassword;
}
else if (key.equals(PwDefsV4.URL_FIELD)) {
protect = mPM.memoryProtection.protectUrl;
}
else if (key.equals(PwDefsV4.NOTES_FIELD)) {
protect = mPM.memoryProtection.protectNotes;
}
}
if (protect) {
xml.attribute(null, AttrProtected, ValTrue);
byte[] data = value.toString().getBytes("UTF-8");
int valLength = data.length;
if (valLength > 0) {
byte[] encoded = new byte[valLength];
randomStream.processBytes(data, 0, valLength, encoded, 0);
xml.text(String.valueOf(Base64Coder.encode(encoded)));
}
}
else {
xml.text(safeXmlString(value.toString()));
}
xml.endTag(null, ElemValue);
xml.endTag(null, ElemString);
}
private void writeObject(String name, PwDeletedObject value) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && value != null);
xml.startTag(null, name);
writeObject(ElemUuid, value.uuid);
writeObject(ElemDeletionTime, value.getDeletionTime());
xml.endTag(null, name);
}
private void writeList(Map<String, ProtectedBinary> binaries) throws IllegalArgumentException, IllegalStateException, IOException {
assert(binaries != null);
for (Entry<String, ProtectedBinary> pair : binaries.entrySet()) {
writeObject(pair.getKey(), pair.getValue(), true);
}
}
private void writeList(String name, List<PwDeletedObject> value) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && value != null);
xml.startTag(null, name);
for (PwDeletedObject pdo : value) {
writeObject(ElemDeletedObject, pdo);
}
xml.endTag(null, name);
}
private void writeList(String name, MemoryProtectionConfig value) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && value != null);
xml.startTag(null, name);
writeObject(ElemProtTitle, value.protectTitle);
writeObject(ElemProtUserName, value.protectUserName);
writeObject(ElemProtPassword, value.protectPassword);
writeObject(ElemProtURL, value.protectUrl);
writeObject(ElemProtNotes, value.protectNotes);
xml.endTag(null, name);
}
private void writeList(String name, Map<String, String> customData) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && customData != null);
xml.startTag(null, name);
for (Entry<String, String> pair : customData.entrySet()) {
writeObject(ElemStringDictExItem, ElemKey, pair.getKey(), ElemValue, pair.getValue());
}
xml.endTag(null, name);
}
private void writeList(String name, ITimeLogger it) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && it != null);
xml.startTag(null, name);
writeObject(ElemLastModTime, it.getLastModificationTime());
writeObject(ElemCreationTime, it.getCreationTime());
writeObject(ElemLastAccessTime, it.getLastAccessTime());
writeObject(ElemExpiryTime, it.getExpiryTime());
writeObject(ElemExpires, it.expires());
writeObject(ElemUsageCount, it.getUsageCount());
writeObject(ElemLocationChanged, it.getLocationChanged());
xml.endTag(null, name);
}
private void writeList(String name, List<PwEntryV4> value, boolean isHistory) throws IllegalArgumentException, IllegalStateException, IOException {
assert(name != null && value != null);
xml.startTag(null, name);
for (PwEntryV4 entry : value) {
writeEntry(entry, isHistory);
}
xml.endTag(null, name);
}
private void writeCustomIconList() throws IllegalArgumentException, IllegalStateException, IOException {
List<PwIconCustom> customIcons = mPM.customIcons;
if (customIcons.size() == 0) return;
xml.startTag(null, ElemCustomIcons);
for (PwIconCustom icon : customIcons) {
xml.startTag(null, ElemCustomIconItem);
writeObject(ElemCustomIconItemID, icon.uuid);
writeObject(ElemCustomIconItemData, String.valueOf(Base64Coder.encode(icon.imageData)));
xml.endTag(null, ElemCustomIconItem);
}
xml.endTag(null, ElemCustomIcons);
}
private void writeBinPool() throws IllegalArgumentException, IllegalStateException, IOException {
xml.startTag(null, ElemBinaries);
for (Entry<Integer, ProtectedBinary> pair : mPM.binPool.entrySet()) {
xml.startTag(null, ElemBinary);
xml.attribute(null, AttrId, Integer.toString(pair.getKey()));
subWriteValue(pair.getValue());
xml.endTag(null, ElemBinary);
}
xml.endTag(null, ElemBinaries);
}
private String safeXmlString(String text) {
if (EmptyUtils.isNullOrEmpty(text)) {
return text;
}
StringBuilder sb = new StringBuilder();
char ch;
for (int i = 0; i < text.length(); i++) {
ch = text.charAt(i);
if(((ch >= 0x20) && (ch <= 0xD7FF)) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD) ||
((ch >= 0xE000) && (ch <= 0xFFFD))) {
sb.append(ch);
}
}
return sb.toString();
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.fileselect;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.kunzisoft.keepass.R;
import com.keepassdroid.utils.Util;
public class BrowserDialog extends Dialog {
public BrowserDialog(Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browser_install);
setTitle(R.string.file_browser);
Button cancel = (Button) findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
BrowserDialog.this.cancel();
}
});
Button market = (Button) findViewById(R.id.install_market);
market.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Util.gotoUrl(getContext(), R.string.oi_filemanager_market);
BrowserDialog.this.cancel();
}
});
if (!isMarketInstalled()) {
market.setVisibility(View.GONE);
}
Button web = (Button) findViewById(R.id.install_web);
web.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Util.gotoUrl(getContext(), R.string.oi_filemanager_web);
BrowserDialog.this.cancel();
}
});
}
private boolean isMarketInstalled() {
PackageManager pm = getContext().getPackageManager();
try {
pm.getPackageInfo("com.android.vending", 0);
} catch (NameNotFoundException e) {
return false;
}
return true;
}
}

View File

@@ -1,48 +0,0 @@
package com.keepassdroid.fragments;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import com.kunzisoft.keepass.R;
public class UnavailableFeatureDialogFragment extends DialogFragment {
private static final String MIN_REQUIRED_VERSION_ARG = "MIN_REQUIRED_VERSION_ARG";
private int minVersionRequired = Build.VERSION_CODES.M;
public static UnavailableFeatureDialogFragment getInstance(int minVersionRequired) {
UnavailableFeatureDialogFragment fragment = new UnavailableFeatureDialogFragment();
Bundle args = new Bundle();
args.putInt(MIN_REQUIRED_VERSION_ARG, minVersionRequired);
fragment.setArguments(args);
return fragment;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (getArguments() != null && getArguments().containsKey(MIN_REQUIRED_VERSION_ARG))
minVersionRequired = getArguments().getInt(MIN_REQUIRED_VERSION_ARG);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
String message = getString(R.string.unavailable_feature_text).concat("\n");
if(Build.VERSION.SDK_INT < minVersionRequired)
message = message.concat(getString(R.string.unavailable_feature_version,
Build.VERSION.SDK_INT,
minVersionRequired));
else
message = message.concat(getString(R.string.unavailable_feature_hardware));
builder.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { }
});
return builder.create();
}
}

View File

@@ -1,7 +0,0 @@
package com.keepassdroid.password;
import android.net.Uri;
interface UriIntentInitTaskCallback {
void onPostInitTask(Uri dbUri, Uri keyFileUri, Integer errorStringId);
}

View File

@@ -1,111 +0,0 @@
package com.keepassdroid.settings;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.keepassdroid.database.Database;
import com.keepassdroid.tasks.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SaveDB;
import com.kunzisoft.keepass.R;
public class RoundsPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
private PwDatabase mPM;
private TextView mRoundsView;
public static RoundsPreferenceDialogFragmentCompat newInstance(
String key) {
final RoundsPreferenceDialogFragmentCompat
fragment = new RoundsPreferenceDialogFragmentCompat();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@Override
public void onDialogClosed(boolean positiveResult) {
if ( positiveResult ) {
long rounds;
try {
String strRounds = mRoundsView.getText().toString();
rounds = Long.parseLong(strRounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_not_number, Toast.LENGTH_LONG).show();
return;
}
if ( rounds < 1 ) {
rounds = 1;
}
long oldRounds = mPM.getNumRounds();
try {
mPM.setNumRounds(rounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_too_large, Toast.LENGTH_LONG).show();
mPM.setNumRounds(Integer.MAX_VALUE);
}
Handler handler = new Handler();
SaveDB save = new SaveDB(getContext(), App.getDB(), new AfterSave(getContext(), handler, oldRounds));
ProgressTask pt = new ProgressTask(getContext(), save, R.string.saving_database);
pt.run();
}
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mRoundsView = (TextView) view.findViewById(R.id.rounds);
// Get the time from the related Preference
Database db = App.getDB();
mPM = db.pm;
long numRounds = mPM.getNumRounds();
DialogPreference preference = getPreference();
if (preference instanceof RoundsPreference) {
numRounds = ((RoundsPreference) preference).getRounds();
}
mRoundsView.setText(String.valueOf(numRounds));
}
private class AfterSave extends OnFinish {
private long mOldRounds;
private Context mCtx;
public AfterSave(Context ctx, Handler handler, long oldRounds) {
super(handler);
mCtx = ctx;
mOldRounds = oldRounds;
}
@Override
public void run() {
if ( mSuccess ) {
} else {
displayMessage(mCtx);
mPM.setNumRounds(mOldRounds);
}
super.run();
}
}
}

View File

@@ -1,28 +0,0 @@
package com.keepassdroid.stylish;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public abstract class StylishActivity extends AppCompatActivity {
private @StyleRes int themeId;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.themeId = Stylish.getThemeId(this);
setTheme(themeId);
}
@Override
protected void onResume() {
super.onResume();
if(Stylish.getThemeId(this) != this.themeId) {
Log.d(this.getClass().getName(), "Theme change detected, restarting activity");
this.recreate();
}
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.utils;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.PwEntry;
public class SprEngine {
private static SprEngineV4 sprV4 = new SprEngineV4();
private static SprEngine spr = new SprEngine();
public static SprEngine getInstance(PwDatabase db) {
if (db instanceof PwDatabaseV4) {
return sprV4;
}
else {
return spr;
}
}
public String compile(String text, PwEntry entry, PwDatabase database) {
return text;
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.utils;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.net.Uri;
import android.text.ClipboardManager;
import android.widget.TextView;
import com.keepassdroid.database.exception.SamsungClipboardException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Util {
public static String getClipboard(Context context) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
CharSequence csText = clipboard.getText();
if (csText == null) {
return "";
}
return csText.toString();
}
public static void copyToClipboard(Context context, String text) throws SamsungClipboardException {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
try {
clipboard.setText(text);
} catch (NullPointerException e) {
throw new SamsungClipboardException(e);
}
}
public static void gotoUrl(Context context, String url) throws ActivityNotFoundException {
if ( url != null && url.length() > 0 ) {
Uri uri = Uri.parse(url);
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
public static void gotoUrl(Context context, int resId) throws ActivityNotFoundException {
gotoUrl(context, context.getString(resId));
}
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int read;
while ((read = in.read(buf)) != -1) {
out.write(buf, 0, read);
}
}
public static void applyFontVisibilityToTextView(boolean applyMonospace, TextView textView) {
if (applyMonospace)
textView.setTypeface(Typeface.MONOSPACE);
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import android.content.Context;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.widget.LinearLayout;
import com.keepassdroid.app.App;
public abstract class ClickView extends LinearLayout {
protected boolean readOnly = false;
public ClickView(Context context) {
super(context);
readOnly = App.getDB().readOnly;
}
abstract public void onClick();
abstract public void onCreateMenu(ContextMenu menu, ContextMenuInfo menuInfo);
abstract public boolean onContextItemSelected(MenuItem item);
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import java.util.ArrayList;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;
public class NoFocusScrollView extends ScrollView {
public NoFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public NoFocusScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoFocusScrollView(Context context) {
super(context);
}
@Override
public ArrayList<View> getFocusables(int direction) {
return new ArrayList<View>();
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.view;
import android.content.Context;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.util.AttributeSet;
import android.widget.TextView;
public class TextViewSelect extends TextView {
public TextViewSelect(Context context) {
this(context, null);
}
public TextViewSelect(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public TextViewSelect(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
setFocusableInTouchMode(true);
}
@Override
protected MovementMethod getDefaultMovementMethod() {
return ArrowKeyMovementMethod.getInstance();
}
@Override
protected boolean getDefaultEditable() {
return false;
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, BufferType.EDITABLE);
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -25,7 +25,7 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.keepassdroid.fileselect.FileSelectActivity; import com.kunzisoft.keepass.fileselect.FileSelectActivity;
public class KeePass extends Activity { public class KeePass extends Activity {

View File

@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.activities; package com.kunzisoft.keepass.activities;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
@@ -27,8 +27,8 @@ import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.TextView; import android.widget.TextView;
import com.keepassdroid.stylish.StylishActivity;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.stylish.StylishActivity;
import org.joda.time.DateTime; import org.joda.time.DateTime;

View File

@@ -0,0 +1,385 @@
/*
*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.activities;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.ExtraFields;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.security.ProtectedString;
import com.kunzisoft.keepass.notifications.NotificationCopyingService;
import com.kunzisoft.keepass.notifications.NotificationField;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.timeout.ClipboardHelper;
import com.kunzisoft.keepass.utils.EmptyUtils;
import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.Util;
import com.kunzisoft.keepass.view.EntryContentsView;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;
import static com.kunzisoft.keepass.settings.PreferencesUtil.isClipboardNotificationsEnable;
public class EntryActivity extends LockingHideActivity {
private final static String TAG = EntryActivity.class.getName();
public static final String KEY_ENTRY = "entry";
private ImageView titleIconView;
private TextView titleView;
private EntryContentsView entryContentsView;
protected PwEntry mEntry;
private boolean mShowPassword;
protected boolean readOnly = false;
private ClipboardHelper clipboardHelper;
private boolean firstLaunchOfActivity;
public static void launch(Activity act, PwEntry pw) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_view);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Database db = App.getDB();
// Likely the app has been killed exit the activity
if ( ! db.getLoaded() ) {
finish();
return;
}
readOnly = db.isReadOnly();
mShowPassword = !PreferencesUtil.isPasswordMask(this);
// Get Entry from UUID
Intent i = getIntent();
UUID uuid = Types.bytestoUUID(i.getByteArrayExtra(KEY_ENTRY));
mEntry = db.getPwDatabase().getEntryByUUIDId(uuid);
if (mEntry == null) {
Toast.makeText(this, R.string.entry_not_found, Toast.LENGTH_LONG).show();
finish();
return;
}
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
invalidateOptionsMenu();
// Update last access time.
mEntry.touch(false, false);
// Get views
titleIconView = findViewById(R.id.entry_icon);
titleView = findViewById(R.id.entry_title);
entryContentsView = findViewById(R.id.entry_contents);
entryContentsView.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this));
// Init the clipboard helper
clipboardHelper = new ClipboardHelper(this);
firstLaunchOfActivity = true;
}
@Override
protected void onResume() {
super.onResume();
// Fill data in resume to update from EntryEditActivity
fillData();
invalidateOptionsMenu();
// Start to manage field reference to copy a value from ref
mEntry.startToManageFieldReferences(App.getDB().getPwDatabase());
// If notifications enabled in settings
// Don't if application timeout
if (firstLaunchOfActivity && !App.isShutdown() && isClipboardNotificationsEnable(getApplicationContext())) {
if (mEntry.getUsername().length() > 0
|| (mEntry.getPassword().length() > 0 && PreferencesUtil.allowCopyPassword(this))
|| mEntry.containsCustomFields()) {
// username already copied, waiting for user's action before copy password.
Intent intent = new Intent(this, NotificationCopyingService.class);
intent.setAction(NotificationCopyingService.ACTION_NEW_NOTIFICATION);
if (mEntry.getTitle() != null)
intent.putExtra(NotificationCopyingService.EXTRA_ENTRY_TITLE, mEntry.getTitle());
// Construct notification fields
ArrayList<NotificationField> notificationFields = new ArrayList<>();
// Add username if exists to notifications
if (mEntry.getUsername().length() > 0)
notificationFields.add(
new NotificationField(
NotificationField.NotificationFieldId.USERNAME,
mEntry.getUsername(),
getResources()));
// Add password to notifications
if (PreferencesUtil.allowCopyPassword(this)) {
if (mEntry.getPassword().length() > 0)
notificationFields.add(
new NotificationField(
NotificationField.NotificationFieldId.PASSWORD,
mEntry.getPassword(),
getResources()));
}
// Add extra fields
if (mEntry.allowExtraFields()) {
try {
mEntry.getFields().doActionToAllCustomProtectedField(new ExtraFields.ActionProtected() {
private int anonymousFieldNumber = 0;
@Override
public void doAction(String key, ProtectedString value) {
notificationFields.add(
new NotificationField(
NotificationField.NotificationFieldId.getAnonymousFieldId()[anonymousFieldNumber],
value.toString(),
key,
getResources()));
anonymousFieldNumber++;
}
});
} catch (ArrayIndexOutOfBoundsException e) {
Log.w(TAG, "Only " + NotificationField.NotificationFieldId.getAnonymousFieldId().length +
" anonymous notifications are available");
}
}
// Add notifications
intent.putParcelableArrayListExtra(NotificationCopyingService.EXTRA_FIELDS, notificationFields);
startService(intent);
}
mEntry.endToManageFieldReferences();
}
firstLaunchOfActivity = false;
}
private void populateTitle(Drawable drawIcon, String text) {
titleIconView.setImageDrawable(drawIcon);
titleView.setText(text);
}
protected void fillData() {
Database db = App.getDB();
PwDatabase pm = db.getPwDatabase();
mEntry.startToManageFieldReferences(pm);
// Assign title
populateTitle(db.getDrawFactory().getIconDrawable(getResources(), mEntry.getIcon()),
mEntry.getTitle());
// Assign basic fields
entryContentsView.assignUserName(mEntry.getUsername());
entryContentsView.assignUserNameCopyListener(view ->
clipboardHelper.timeoutCopyToClipboard(mEntry.getUsername(),
getString(R.string.copy_field, getString(R.string.entry_user_name)))
);
entryContentsView.assignPassword(mEntry.getPassword());
if (PreferencesUtil.allowCopyPassword(this)) {
entryContentsView.assignPasswordCopyListener(view ->
clipboardHelper.timeoutCopyToClipboard(mEntry.getPassword(),
getString(R.string.copy_field, getString(R.string.entry_password)))
);
}
entryContentsView.assignURL(mEntry.getUrl());
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
entryContentsView.assignComment(mEntry.getNotes());
// Assign custom fields
if (mEntry.allowExtraFields()) {
entryContentsView.clearExtraFields();
mEntry.getFields().doActionToAllCustomProtectedField((label, value) ->
entryContentsView.addExtraField(label, value, view ->
clipboardHelper.timeoutCopyToClipboard(
value.toString(),
getString(R.string.copy_field, label)
)
));
}
// Assign dates
entryContentsView.assignCreationDate(mEntry.getCreationTime().getDate());
entryContentsView.assignModificationDate(mEntry.getLastModificationTime().getDate());
entryContentsView.assignLastAccessDate(mEntry.getLastAccessTime().getDate());
Date expires = mEntry.getExpiryTime().getDate();
if ( mEntry.isExpires() ) {
entryContentsView.assignExpiresDate(expires);
} else {
entryContentsView.assignExpiresDate(getString(R.string.never));
}
mEntry.endToManageFieldReferences();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE:
fillData();
break;
}
}
private void changeShowPasswordIcon(MenuItem togglePassword) {
if ( mShowPassword ) {
togglePassword.setTitle(R.string.menu_hide_password);
togglePassword.setIcon(R.drawable.ic_visibility_off_white_24dp);
} else {
togglePassword.setTitle(R.string.menu_showpass);
togglePassword.setIcon(R.drawable.ic_visibility_white_24dp);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
MenuUtil.donationMenuInflater(inflater, menu);
inflater.inflate(R.menu.entry, menu);
inflater.inflate(R.menu.database_lock, menu);
if (readOnly) {
MenuItem edit = menu.findItem(R.id.menu_edit);
if (edit != null)
edit.setVisible(false);
}
MenuItem togglePassword = menu.findItem(R.id.menu_toggle_pass);
if (entryContentsView != null && togglePassword != null) {
if (entryContentsView.isPasswordPresent() || entryContentsView.atLeastOneFieldProtectedPresent()) {
changeShowPasswordIcon(togglePassword);
} else {
togglePassword.setVisible(false);
}
}
MenuItem gotoUrl = menu.findItem(R.id.menu_goto_url);
if (gotoUrl != null) {
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
// so mEntry may not be set
if (mEntry == null) {
gotoUrl.setVisible(false);
} else {
String url = mEntry.getUrl();
if (EmptyUtils.isNullOrEmpty(url)) {
// disable button if url is not available
gotoUrl.setVisible(false);
}
}
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.menu_donate:
return MenuUtil.onDonationItemSelected(this);
case R.id.menu_toggle_pass:
mShowPassword = !mShowPassword;
changeShowPasswordIcon(item);
entryContentsView.setHiddenPasswordStyle(!mShowPassword);
return true;
case R.id.menu_edit:
EntryEditActivity.launch(EntryActivity.this, mEntry);
return true;
case R.id.menu_goto_url:
String url;
url = mEntry.getUrl();
// Default http:// if no protocol specified
if ( ! url.contains("://") ) {
url = "http://" + url;
}
try {
Util.gotoUrl(this, url);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show();
}
return true;
case R.id.menu_lock:
lockAndExit();
return true;
case android.R.id.home :
finish(); // close this activity and return to preview activity (if there is any)
}
return super.onOptionsItemSelected(item);
}
@Override
public void finish() {
// Transit data in previous Activity after an update
/*
TODO Slowdown when add entry as result
Intent intent = new Intent();
intent.putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntry);
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, intent);
*/
super.finish();
}
}

View File

@@ -0,0 +1,407 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Toast;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwDate;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwGroupId;
import com.kunzisoft.keepass.database.PwIconStandard;
import com.kunzisoft.keepass.database.edit.AddEntry;
import com.kunzisoft.keepass.database.edit.OnFinish;
import com.kunzisoft.keepass.database.edit.RunnableOnFinish;
import com.kunzisoft.keepass.database.edit.UpdateEntry;
import com.kunzisoft.keepass.database.security.ProtectedString;
import com.kunzisoft.keepass.dialogs.GeneratePasswordDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
import com.kunzisoft.keepass.icons.Icons;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.tasks.ProgressTask;
import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.Util;
import com.kunzisoft.keepass.view.EntryEditCustomField;
import java.util.UUID;
public class EntryEditActivity extends LockingHideActivity
implements IconPickerDialogFragment.IconPickerListener,
GeneratePasswordDialogFragment.GeneratePasswordListener {
private static final String TAG = EntryEditActivity.class.getName();
// Keys for current Activity
public static final String KEY_ENTRY = "entry";
public static final String KEY_PARENT = "parent";
// Keys for callback
public static final int ADD_ENTRY_RESULT_CODE = 31;
public static final int UPDATE_ENTRY_RESULT_CODE = 32;
public static final int ADD_OR_UPDATE_ENTRY_REQUEST_CODE = 7129;
public static final String ADD_OR_UPDATE_ENTRY_KEY = "ADD_OR_UPDATE_ENTRY_KEY";
protected PwEntry mEntry;
protected PwEntry mCallbackNewEntry;
protected boolean mIsNew;
protected int mSelectedIconID = -1;
// Views
private ScrollView scrollView;
private EditText entryTitleView;
private EditText entryUserNameView;
private EditText entryUrlView;
private EditText entryPasswordView;
private EditText entryConfirmationPasswordView;
private EditText entryCommentView;
private ViewGroup entryExtraFieldsContainer;
/**
* launch EntryEditActivity to update an existing entry
* @param act from activity
* @param pw Entry to update
*/
public static void launch(Activity act, PwEntry pw) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryEditActivity.class);
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
/**
* launch EntryEditActivity to add a new entry
* @param act from activity
* @param pwGroup Group who will contains new entry
*/
public static void launch(Activity act, PwGroup pwGroup) {
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
Intent intent = new Intent(act, EntryEditActivity.class);
intent.putExtra(KEY_PARENT, pwGroup.getId());
act.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_edit);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.app_name));
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
scrollView = findViewById(R.id.entry_scroll);
scrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
entryTitleView = findViewById(R.id.entry_title);
entryUserNameView = findViewById(R.id.entry_user_name);
entryUrlView = findViewById(R.id.entry_url);
entryPasswordView = findViewById(R.id.entry_password);
entryConfirmationPasswordView = findViewById(R.id.entry_confpassword);
entryCommentView = findViewById(R.id.entry_comment);
entryExtraFieldsContainer = findViewById(R.id.advanced_container);
// Likely the app has been killed exit the activity
Database db = App.getDB();
if ( ! db.getLoaded() ) {
finish();
return;
}
Intent intent = getIntent();
byte[] uuidBytes = intent.getByteArrayExtra(KEY_ENTRY);
PwDatabase pm = db.getPwDatabase();
if ( uuidBytes == null ) {
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
PwGroup parent = pm.getGroupByGroupId(parentId);
mEntry = PwEntry.getInstance(parent);
mIsNew = true;
} else {
UUID uuid = Types.bytestoUUID(uuidBytes);
mEntry = pm.getEntryByUUIDId(uuid);
mIsNew = false;
fillData();
}
View iconButton = findViewById(R.id.icon_button);
iconButton.setOnClickListener(v ->
IconPickerDialogFragment.launch(EntryEditActivity.this));
// Generate password button
View generatePassword = findViewById(R.id.generate_button);
generatePassword.setOnClickListener(v -> {
GeneratePasswordDialogFragment generatePasswordDialogFragment = new GeneratePasswordDialogFragment();
generatePasswordDialogFragment.show(getSupportFragmentManager(), "PasswordGeneratorFragment");
});
// Save button
View save = findViewById(R.id.entry_save);
save.setOnClickListener(v -> {
if (!validateBeforeSaving()) {
return;
}
mCallbackNewEntry = populateNewEntry();
OnFinish onFinish = new AfterSave();
EntryEditActivity act = EntryEditActivity.this;
RunnableOnFinish task;
if ( mIsNew ) {
task = new AddEntry(act, App.getDB(), mCallbackNewEntry, onFinish);
} else {
task = new UpdateEntry(act, App.getDB(), mEntry, mCallbackNewEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
});
if (mEntry.allowExtraFields()) {
View add = findViewById(R.id.add_new_field);
add.setVisibility(View.VISIBLE);
add.setOnClickListener(v -> {
EntryEditCustomField ees = new EntryEditCustomField(EntryEditActivity.this);
ees.setData("", new ProtectedString(false, ""));
entryExtraFieldsContainer.addView(ees);
// Scroll bottom
scrollView.post(() -> scrollView.fullScroll(ScrollView.FOCUS_DOWN));
});
}
}
protected boolean validateBeforeSaving() {
// Require title
String title = entryTitleView.getText().toString();
if ( title.length() == 0 ) {
Toast.makeText(this, R.string.error_title_required, Toast.LENGTH_LONG).show();
return false;
}
// Validate password
String pass = entryPasswordView.getText().toString();
String conf = entryConfirmationPasswordView.getText().toString();
if ( ! pass.equals(conf) ) {
Toast.makeText(this, R.string.error_pass_match, Toast.LENGTH_LONG).show();
return false;
}
// Validate extra fields
if (mEntry.allowExtraFields()) {
for (int i = 0; i < entryExtraFieldsContainer.getChildCount(); i++) {
EntryEditCustomField entryEditCustomField = (EntryEditCustomField) entryExtraFieldsContainer.getChildAt(i);
String key = entryEditCustomField.getLabel();
if (key == null || key.length() == 0) {
Toast.makeText(this, R.string.error_string_key, Toast.LENGTH_LONG).show();
return false;
}
}
}
return true;
}
protected PwEntry populateNewEntry() {
PwDatabase db = App.getDB().getPwDatabase();
PwEntry newEntry = mEntry.clone();
newEntry.startToManageFieldReferences(db);
newEntry.createBackup(db);
newEntry.setLastAccessTime(new PwDate());
newEntry.setLastModificationTime(new PwDate());
newEntry.setTitle(entryTitleView.getText().toString());
if(mSelectedIconID != -1)
// or TODO icon factory newEntry.setIcon(App.getDB().pm.iconFactory.getIcon(mSelectedIconID));
newEntry.setIcon(new PwIconStandard(mSelectedIconID));
else {
if (mIsNew) {
newEntry.setIcon(App.getDB().getPwDatabase().getIconFactory().getFirstIcon());
}
else {
// Keep previous icon, if no new one was selected
newEntry.setIcon(mEntry.getIconStandard());
}
}
newEntry.setUrl(entryUrlView.getText().toString());
newEntry.setUsername(entryUserNameView.getText().toString());
newEntry.setNotes(entryCommentView.getText().toString());
newEntry.setPassword(entryPasswordView.getText().toString());
if (newEntry.allowExtraFields()) {
// Delete all extra strings
newEntry.removeAllCustomFields();
// Add extra fields from views
for (int i = 0; i < entryExtraFieldsContainer.getChildCount(); i++) {
EntryEditCustomField view = (EntryEditCustomField) entryExtraFieldsContainer.getChildAt(i);
String key = view.getLabel();
String value = view.getValue();
boolean protect = view.isProtected();
newEntry.addExtraField(key, new ProtectedString(protect, value));
}
}
newEntry.endToManageFieldReferences();
return newEntry;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
MenuUtil.donationMenuInflater(inflater, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.menu_donate:
return MenuUtil.onDonationItemSelected(this);
case android.R.id.home:
finish();
}
return super.onOptionsItemSelected(item);
}
protected void fillData() {
ImageButton currIconButton = findViewById(R.id.icon_button);
App.getDB().getDrawFactory().assignDrawableTo(currIconButton, getResources(), mEntry.getIcon());
// Don't start the field reference manager, we want to see the raw ref
mEntry.endToManageFieldReferences();
entryTitleView.setText(mEntry.getTitle());
entryUserNameView.setText(mEntry.getUsername());
entryUrlView.setText(mEntry.getUrl());
String password = mEntry.getPassword();
entryPasswordView.setText(password);
entryConfirmationPasswordView.setText(password);
entryCommentView.setText(mEntry.getNotes());
boolean visibilityFontActivated = PreferencesUtil.fieldFontIsInVisibility(this);
if (visibilityFontActivated) {
Util.applyFontVisibilityTo(entryUserNameView);
Util.applyFontVisibilityTo(entryPasswordView);
Util.applyFontVisibilityTo(entryConfirmationPasswordView);
Util.applyFontVisibilityTo(entryCommentView);
}
if (mEntry.allowExtraFields()) {
LinearLayout container = findViewById(R.id.advanced_container);
mEntry.getFields().doActionToAllCustomProtectedField((key, value) -> {
EntryEditCustomField entryEditCustomField = new EntryEditCustomField(EntryEditActivity.this);
entryEditCustomField.setData(key, value);
entryEditCustomField.setFontVisibility(visibilityFontActivated);
container.addView(entryEditCustomField);
});
}
}
@Override
public void iconPicked(Bundle bundle) {
mSelectedIconID = bundle.getInt(IconPickerDialogFragment.KEY_ICON_ID);
ImageButton currIconButton = findViewById(R.id.icon_button);
currIconButton.setImageResource(Icons.iconToResId(mSelectedIconID));
}
@Override
public void acceptPassword(Bundle bundle) {
String generatedPassword = bundle.getString(GeneratePasswordDialogFragment.KEY_PASSWORD_ID);
entryPasswordView.setText(generatedPassword);
entryConfirmationPasswordView.setText(generatedPassword);
}
@Override
public void cancelPassword(Bundle bundle) {
// Do nothing here
}
@Override
public void finish() {
// Assign entry callback as a result in all case
try {
if (mCallbackNewEntry != null) {
Bundle bundle = new Bundle();
Intent intentEntry = new Intent();
bundle.putSerializable(ADD_OR_UPDATE_ENTRY_KEY, mCallbackNewEntry);
intentEntry.putExtras(bundle);
if (mIsNew) {
setResult(ADD_ENTRY_RESULT_CODE, intentEntry);
} else {
setResult(UPDATE_ENTRY_RESULT_CODE, intentEntry);
}
}
super.finish();
} catch (Exception e) {
// Exception when parcelable can't be done
Log.e(TAG, "Cant add entry as result", e);
}
}
private final class AfterSave extends OnFinish {
AfterSave() {
super(new Handler());
}
@Override
public void run() {
if ( mSuccess ) {
finish();
} else {
displayMessage(EntryEditActivity.this);
}
}
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.activities; package com.kunzisoft.keepass.activities;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
@@ -39,42 +39,41 @@ import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import com.keepassdroid.adapters.NodeAdapter;
import com.keepassdroid.app.App;
import com.keepassdroid.autofill.AutofillHelper;
import com.keepassdroid.database.Database;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupId;
import com.keepassdroid.database.PwNode;
import com.keepassdroid.database.SortNodeEnum;
import com.keepassdroid.database.edit.AddGroup;
import com.keepassdroid.database.edit.DeleteEntry;
import com.keepassdroid.database.edit.DeleteGroup;
import com.keepassdroid.dialog.ReadOnlyDialog;
import com.keepassdroid.fragments.AssignMasterKeyDialogFragment;
import com.keepassdroid.fragments.GroupEditDialogFragment;
import com.keepassdroid.fragments.IconPickerDialogFragment;
import com.keepassdroid.password.PasswordActivity;
import com.keepassdroid.search.SearchResultsActivity;
import com.keepassdroid.tasks.ProgressTask;
import com.keepassdroid.view.ListNodesWithAddButtonView;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.adapters.NodeAdapter;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.autofill.AutofillHelper;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwGroupId;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.database.edit.AddGroup;
import com.kunzisoft.keepass.database.edit.DeleteEntry;
import com.kunzisoft.keepass.database.edit.DeleteGroup;
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
import com.kunzisoft.keepass.search.SearchResultsActivity;
import com.kunzisoft.keepass.tasks.ProgressTask;
import com.kunzisoft.keepass.view.AddNodeButtonView;
public class GroupActivity extends ListNodesActivity public class GroupActivity extends ListNodesActivity
implements GroupEditDialogFragment.EditGroupListener, IconPickerDialogFragment.IconPickerListener { implements GroupEditDialogFragment.EditGroupListener, IconPickerDialogFragment.IconPickerListener {
private static final String GROUP_ID_KEY = "GROUP_ID_KEY";
private AddNodeButtonView addNodeButtonView;
protected boolean addGroupEnabled = false; protected boolean addGroupEnabled = false;
protected boolean addEntryEnabled = false; protected boolean addEntryEnabled = false;
protected boolean isRoot = false; protected boolean isRoot = false;
protected boolean readOnly = false; protected boolean readOnly = false;
protected EditGroupDialogAction editGroupDialogAction = EditGroupDialogAction.NONE; protected EditGroupDialogAction editGroupDialogAction = EditGroupDialogAction.NONE;
private ListNodesWithAddButtonView rootView;
private AutofillHelper autofillHelper;
private enum EditGroupDialogAction { private enum EditGroupDialogAction {
CREATION, UPDATE, NONE CREATION, UPDATE, NONE
@@ -83,31 +82,41 @@ public class GroupActivity extends ListNodesActivity
private static final String TAG = "Group Activity:"; private static final String TAG = "Group Activity:";
public static void launch(Activity act) { public static void launch(Activity act) {
launch(act, (PwGroup) null); recordFirstTimeBeforeLaunch(act);
launch(act, (PwGroup) null);
} }
public static void launch(Activity act, PwGroup group) { public static void launch(Activity act, PwGroup group) {
Intent intent = new Intent(act, GroupActivity.class); if (checkTimeIsAllowedOrFinish(act)) {
if ( group != null ) { Intent intent = new Intent(act, GroupActivity.class);
intent.putExtra(KEY_ENTRY, group.getId()); if (group != null) {
intent.putExtra(GROUP_ID_KEY, group.getId());
}
act.startActivityForResult(intent, 0);
} }
act.startActivityForResult(intent, 0);
} }
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
public static void launch(Activity act, AssistStructure assistStructure) { public static void launch(Activity act, AssistStructure assistStructure) {
launch(act, null, assistStructure); if ( assistStructure != null ) {
recordFirstTimeBeforeLaunch(act);
launch(act, null, assistStructure);
} else {
launch(act);
}
} }
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
public static void launch(Activity act, PwGroup group, AssistStructure assistStructure) { public static void launch(Activity act, PwGroup group, AssistStructure assistStructure) {
if ( assistStructure != null ) { if ( assistStructure != null ) {
Intent intent = new Intent(act, GroupActivity.class); if (checkTimeIsAllowedOrFinish(act)) {
if ( group != null ) { Intent intent = new Intent(act, GroupActivity.class);
intent.putExtra(KEY_ENTRY, group.getId()); if (group != null) {
intent.putExtra(GROUP_ID_KEY, group.getId());
}
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
} }
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
} else { } else {
launch(act, group); launch(act, group);
} }
@@ -124,40 +133,34 @@ public class GroupActivity extends ListNodesActivity
} }
// Construct main view // Construct main view
rootView = new ListNodesWithAddButtonView(this); setContentView(getLayoutInflater().inflate(R.layout.list_nodes_with_add_button, null));
rootView.enableAddGroup(addGroupEnabled);
rootView.enableAddEntry(addEntryEnabled);
setContentView(rootView);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); addNodeButtonView = findViewById(R.id.add_node_button);
addNodeButtonView.enableAddGroup(addGroupEnabled);
addNodeButtonView.enableAddEntry(addEntryEnabled);
// Hide when scroll
RecyclerView recyclerView = findViewById(R.id.nodes_list);
recyclerView.addOnScrollListener(addNodeButtonView.hideButtonOnScrollListener());
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(""); toolbar.setTitle("");
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
if ( mCurrentGroup.getParent() != null ) if ( mCurrentGroup.getParent() != null )
toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp); toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
rootView.setAddGroupClickListener(new View.OnClickListener() { addNodeButtonView.setAddGroupClickListener(v -> {
public void onClick(View v) { editGroupDialogAction = EditGroupDialogAction.CREATION;
editGroupDialogAction = EditGroupDialogAction.CREATION; GroupEditDialogFragment groupEditDialogFragment = new GroupEditDialogFragment();
GroupEditDialogFragment groupEditDialogFragment = new GroupEditDialogFragment(); groupEditDialogFragment.show(getSupportFragmentManager(),
groupEditDialogFragment.show(getSupportFragmentManager(), GroupEditDialogFragment.TAG_CREATE_GROUP);
GroupEditDialogFragment.TAG_CREATE_GROUP);
}
});
rootView.setAddEntryClickListener(new View.OnClickListener() {
public void onClick(View v) {
EntryEditActivity.Launch(GroupActivity.this, mCurrentGroup);
}
}); });
addNodeButtonView.setAddEntryClickListener(v ->
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
setGroupTitle(); setGroupTitle();
setGroupIcon(); setGroupIcon();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
autofillHelper = new AutofillHelper();
autofillHelper.retrieveAssistStructure(getIntent());
}
Log.w(TAG, "Finished creating tree"); Log.w(TAG, "Finished creating tree");
if (isRoot) { if (isRoot) {
@@ -168,23 +171,24 @@ public class GroupActivity extends ListNodesActivity
protected PwGroup initCurrentGroup() { protected PwGroup initCurrentGroup() {
PwGroup currentGroup; PwGroup currentGroup;
Database db = App.getDB(); Database db = App.getDB();
readOnly = db.readOnly; readOnly = db.isReadOnly();
PwGroup root = db.pm.rootGroup; PwGroup root = db.getPwDatabase().getRootGroup();
Log.w(TAG, "Creating tree view"); Log.w(TAG, "Creating tree view");
PwGroupId pwGroupId = (PwGroupId) getIntent().getSerializableExtra(KEY_ENTRY); PwGroupId pwGroupId = (PwGroupId) getIntent().getSerializableExtra(GROUP_ID_KEY);
if ( pwGroupId == null ) { if ( pwGroupId == null ) {
currentGroup = root; currentGroup = root;
} else { } else {
currentGroup = db.pm.groups.get(pwGroupId); currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
} }
addGroupEnabled = !readOnly; if (currentGroup != null) {
addEntryEnabled = !readOnly; addGroupEnabled = !readOnly;
addEntryEnabled = !readOnly; // TODO ReadOnly
isRoot = (currentGroup == root); isRoot = (currentGroup == root);
if ( !currentGroup.allowAddEntryIfIsRoot() ) if (!currentGroup.allowAddEntryIfIsRoot())
addEntryEnabled = !isRoot && addEntryEnabled; addEntryEnabled = !isRoot && addEntryEnabled;
}
return currentGroup; return currentGroup;
} }
@@ -194,31 +198,6 @@ public class GroupActivity extends ListNodesActivity
return (RecyclerView) findViewById(R.id.nodes_list); return (RecyclerView) findViewById(R.id.nodes_list);
} }
@Override
public void onNodeClick(PwNode node) {
// Add event when we have Autofill
AssistStructure assistStructure = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
assistStructure = autofillHelper.getAssistStructure();
if (assistStructure != null) {
mAdapter.registerANodeToUpdate(node);
switch (node.getType()) {
case GROUP:
GroupActivity.launch(this, (PwGroup) node, assistStructure);
break;
case ENTRY:
// Build response with the entry selected
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
finish();
break;
}
}
}
if ( assistStructure == null ){
super.onNodeClick(node);
}
}
@Override @Override
protected void addOptionsToAdapter(NodeAdapter nodeAdapter) { protected void addOptionsToAdapter(NodeAdapter nodeAdapter) {
super.addOptionsToAdapter(nodeAdapter); super.addOptionsToAdapter(nodeAdapter);
@@ -251,7 +230,7 @@ public class GroupActivity extends ListNodesActivity
GroupEditDialogFragment.TAG_CREATE_GROUP); GroupEditDialogFragment.TAG_CREATE_GROUP);
break; break;
case ENTRY: case ENTRY:
EntryEditActivity.Launch(GroupActivity.this, (PwEntry) node); EntryEditActivity.launch(GroupActivity.this, (PwEntry) node);
break; break;
} }
return true; return true;
@@ -276,30 +255,27 @@ public class GroupActivity extends ListNodesActivity
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
// Show button on resume // Show button on resume
rootView.showButton(); addNodeButtonView.showButton();
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onStop() {
super.onActivityResult(requestCode, resultCode, data); super.onStop();
// Hide button
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { addNodeButtonView.hideButton();
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
} }
@Override @Override
public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) { public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) {
super.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom); super.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom);
// Show button if hide after sort // Show button if hide after sort
rootView.showButton(); addNodeButtonView.showButton();
} }
protected void setGroupIcon() { protected void setGroupIcon() {
if (mCurrentGroup != null) { if (mCurrentGroup != null) {
ImageView iv = (ImageView) findViewById(R.id.icon); ImageView iv = findViewById(R.id.icon);
App.getDB().drawFactory.assignDrawableTo(iv, getResources(), mCurrentGroup.getIcon()); App.getDB().getDrawFactory().assignDrawableTo(iv, getResources(), mCurrentGroup.getIcon());
} }
} }
@@ -339,6 +315,7 @@ public class GroupActivity extends ListNodesActivity
searchView = (SearchView) searchItem.getActionView(); searchView = (SearchView) searchItem.getActionView();
} }
if (searchView != null) { if (searchView != null) {
// TODO Flickering when locking, will be better with content provider
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, SearchResultsActivity.class))); searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, SearchResultsActivity.class)));
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
} }
@@ -346,6 +323,30 @@ public class GroupActivity extends ListNodesActivity
return true; return true;
} }
@Override
public void startActivity(Intent intent) {
boolean customSearchQueryExecuted = false;
// Get the intent, verify the action and get the query
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
// manually launch the real search activity
final Intent searchIntent = new Intent(getApplicationContext(), SearchResultsActivity.class);
// add query to the Intent Extras
searchIntent.putExtra(SearchManager.QUERY, query);
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& autofillHelper.getAssistStructure() != null ) {
AutofillHelper.addAssistStructureExtraInIntent(searchIntent, autofillHelper.getAssistStructure());
startActivityForResult(searchIntent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
customSearchQueryExecuted = true;
}
}
if (!customSearchQueryExecuted) {
super.startActivity(intent);
}
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
@@ -359,9 +360,7 @@ public class GroupActivity extends ListNodesActivity
return true; return true;
case R.id.menu_lock: case R.id.menu_lock:
App.setShutdown(); lockAndExit();
setResult(PasswordActivity.RESULT_EXIT_LOCK);
finish();
return true; return true;
case R.id.menu_change_master_key: case R.id.menu_change_master_key:
@@ -414,7 +413,7 @@ public class GroupActivity extends ListNodesActivity
} }
protected void showWarnings() { protected void showWarnings() {
if (App.getDB().readOnly) { if (App.getDB().isReadOnly()) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getBoolean(getString(R.string.show_read_only_warning), true)) { if (prefs.getBoolean(getString(R.string.show_read_only_warning), true)) {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,8 +17,10 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.activities; package com.kunzisoft.keepass.activities;
import android.annotation.SuppressLint;
import android.app.assist.AssistStructure;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
@@ -36,37 +38,38 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import com.keepassdroid.adapters.NodeAdapter;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ActivityCompat;
import com.keepassdroid.compat.EditorCompat;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwNode;
import com.keepassdroid.database.edit.AfterAddNodeOnFinish;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.fragments.AssignMasterKeyDialogFragment;
import com.keepassdroid.fragments.SortDialogFragment;
import com.keepassdroid.settings.PreferencesUtil;
import com.keepassdroid.tasks.UIToastTask;
import com.keepassdroid.utils.MenuUtil;
import com.keepassdroid.database.SortNodeEnum;
import com.keepassdroid.view.AssignPasswordHelper;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.adapters.NodeAdapter;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.autofill.AutofillHelper;
import com.kunzisoft.keepass.compat.EditorCompat;
import com.kunzisoft.keepass.database.Database;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.database.edit.AfterAddNodeOnFinish;
import com.kunzisoft.keepass.database.edit.OnFinish;
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
import com.kunzisoft.keepass.password.AssignPasswordHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.tasks.UIToastTask;
import com.kunzisoft.keepass.utils.MenuUtil;
public abstract class ListNodesActivity extends LockingActivity public abstract class ListNodesActivity extends LockingActivity
implements AssignMasterKeyDialogFragment.AssignPasswordDialogListener, implements AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
NodeAdapter.OnNodeClickCallback, NodeAdapter.OnNodeClickCallback,
SortDialogFragment.SortSelectionListener { SortDialogFragment.SortSelectionListener {
public static final String KEY_ENTRY = "entry";
protected PwGroup mCurrentGroup; protected PwGroup mCurrentGroup;
protected NodeAdapter mAdapter; protected NodeAdapter mAdapter;
private SharedPreferences prefs; private SharedPreferences prefs;
protected AutofillHelper autofillHelper;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -76,21 +79,27 @@ public abstract class ListNodesActivity extends LockingActivity
} }
// Likely the app has been killed exit the activity // Likely the app has been killed exit the activity
if ( ! App.getDB().Loaded() ) { if ( ! App.getDB().getLoaded() ) {
finish(); finish();
return; return;
} }
prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs = PreferenceManager.getDefaultSharedPreferences(this);
ActivityCompat.invalidateOptionsMenu(this); invalidateOptionsMenu();
// TODO Move in search
setContentView(R.layout.list_nodes); setContentView(R.layout.list_nodes);
mCurrentGroup = initCurrentGroup(); mCurrentGroup = initCurrentGroup();
mAdapter = new NodeAdapter(this); mAdapter = new NodeAdapter(this);
addOptionsToAdapter(mAdapter); addOptionsToAdapter(mAdapter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
autofillHelper = new AutofillHelper();
autofillHelper.retrieveAssistStructure(getIntent());
}
} }
protected abstract PwGroup initCurrentGroup(); protected abstract PwGroup initCurrentGroup();
@@ -112,7 +121,7 @@ public abstract class ListNodesActivity extends LockingActivity
protected void setGroupTitle() { protected void setGroupTitle() {
if ( mCurrentGroup != null ) { if ( mCurrentGroup != null ) {
String name = mCurrentGroup.getName(); String name = mCurrentGroup.getName();
TextView tv = (TextView) findViewById(R.id.group_name); TextView tv = findViewById(R.id.group_name);
if ( name != null && name.length() > 0 ) { if ( name != null && name.length() > 0 ) {
if ( tv != null ) { if ( tv != null ) {
tv.setText(name); tv.setText(name);
@@ -127,21 +136,41 @@ public abstract class ListNodesActivity extends LockingActivity
protected void assignListToNodeAdapter(RecyclerView recyclerView) { protected void assignListToNodeAdapter(RecyclerView recyclerView) {
recyclerView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); recyclerView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
// TODO mList.setTextFilterEnabled(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mAdapter); recyclerView.setAdapter(mAdapter);
} }
@Override @Override
public void onNodeClick(PwNode node) { public void onNodeClick(PwNode node) {
mAdapter.registerANodeToUpdate(node);
switch (node.getType()) { mAdapter.registerANodeToUpdate(node);
case GROUP:
GroupActivity.launch(this, (PwGroup) node); // Add event when we have Autofill
break; AssistStructure assistStructure = null;
case ENTRY: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
EntryActivity.launch(this, (PwEntry) node); assistStructure = autofillHelper.getAssistStructure();
break; if (assistStructure != null) {
switch (node.getType()) {
case GROUP:
GroupActivity.launch(this, (PwGroup) node, assistStructure);
break;
case ENTRY:
// Build response with the entry selected
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
finish();
break;
}
}
}
if ( assistStructure == null ){
switch (node.getType()) {
case GROUP:
GroupActivity.launch(this, (PwGroup) node);
break;
case ENTRY:
EntryActivity.launch(this, (PwEntry) node);
break;
}
} }
} }
@@ -179,10 +208,10 @@ public abstract class ListNodesActivity extends LockingActivity
case R.id.menu_sort: case R.id.menu_sort:
SortDialogFragment sortDialogFragment; SortDialogFragment sortDialogFragment;
PwDatabase database = App.getDB().pm; PwDatabase database = App.getDB().getPwDatabase();
/* /*
// TODO Recycle bin bottom // TODO Recycle bin bottom
if (database.isRecycleBinAvailable() && database.isRecycleBinEnable()) { if (database.isRecycleBinAvailable() && database.isRecycleBinEnabled()) {
sortDialogFragment = sortDialogFragment =
SortDialogFragment.getInstance( SortDialogFragment.getInstance(
PrefsUtil.getListSort(this), PrefsUtil.getListSort(this),
@@ -202,7 +231,8 @@ public abstract class ListNodesActivity extends LockingActivity
return true; return true;
default: default:
MenuUtil.onDefaultMenuOptionsItemSelected(this, item); // Check the time lock before launching settings
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, true);
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }
@@ -228,6 +258,7 @@ public abstract class ListNodesActivity extends LockingActivity
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) { switch (requestCode) {
case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE: case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE:
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE || if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE ||
@@ -246,9 +277,14 @@ public abstract class ListNodesActivity extends LockingActivity
} }
break; break;
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
} }
@Override @SuppressLint("RestrictedApi")
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
/* /*
* ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in * ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
@@ -294,11 +330,14 @@ public abstract class ListNodesActivity extends LockingActivity
if ( mSuccess) { if ( mSuccess) {
mAdapter.removeNode(pwNode); mAdapter.removeNode(pwNode);
PwGroup parent = pwNode.getParent(); PwGroup parent = pwNode.getParent();
PwDatabase database = App.getDB().pm; Database db = App.getDB();
if (database.isRecycleBinAvailable() && database.isRecycleBinEnable()) { PwDatabase database = db.getPwDatabase();
if (db.isRecycleBinAvailable() &&
db.isRecycleBinEnabled()) {
PwGroup recycleBin = database.getRecycleBin(); PwGroup recycleBin = database.getRecycleBin();
// Add trash if it doesn't exists // Add trash if it doesn't exists
if (parent.equals(recycleBin) if (parent.equals(recycleBin)
&& mCurrentGroup != null
&& mCurrentGroup.getParent() == null && mCurrentGroup.getParent() == null
&& !mCurrentGroup.equals(recycleBin)) { && !mCurrentGroup.equals(recycleBin)) {
mAdapter.addNode(parent); mAdapter.addNode(parent);

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.activities;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.stylish.StylishActivity;
import com.kunzisoft.keepass.timeout.TimeoutHelper;
public abstract class LockingActivity extends StylishActivity {
private static final String TAG = LockingActivity.class.getName();
public static final int RESULT_EXIT_LOCK = 1450;
private static final String AT_LEAST_SECOND_SHOWN_KEY = "AT_LEAST_SECOND_SHOWN_KEY";
private ScreenReceiver screenReceiver;
private boolean exitLock;
protected static void recordFirstTimeBeforeLaunch(Activity activity) {
TimeoutHelper.recordTime(activity);
}
protected static boolean checkTimeIsAllowedOrFinish(Activity activity) {
return TimeoutHelper.checkTime(activity);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(this)) {
screenReceiver = new ScreenReceiver();
registerReceiver(screenReceiver, new IntentFilter((Intent.ACTION_SCREEN_OFF)));
} else
screenReceiver = null;
exitLock = false;
// WARNING TODO recordTime is not called after a back if was in backstack
}
public static void checkShutdown(Activity act) {
if (App.isShutdown() && App.getDB().getLoaded()) {
Log.i(TAG, "Shutdown " + act.getLocalClassName() +
" after inactivity or manual lock");
act.setResult(RESULT_EXIT_LOCK);
act.finish();
}
}
protected void lockAndExit() {
App.setShutdown();
setResult(LockingActivity.RESULT_EXIT_LOCK);
finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_EXIT_LOCK) {
exitLock = true;
checkShutdown(this);
}
}
@Override
protected void onResume() {
super.onResume();
// After the first creation
// or If simply swipe with another application
// If the time is out -> close the Activity
TimeoutHelper.checkTime(this);
// If onCreate already record time
if (!exitLock)
TimeoutHelper.recordTime(this);
}
@Override
protected void onPause() {
super.onPause();
// If the time is out during our navigation in activity -> close the Activity
TimeoutHelper.checkTime(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(screenReceiver != null)
unregisterReceiver(screenReceiver);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AT_LEAST_SECOND_SHOWN_KEY, true);
}
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(LockingActivity.this)) {
App.setShutdown();
checkShutdown(LockingActivity.this);
}
}
}
}
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,14 +17,14 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.activities; package com.kunzisoft.keepass.activities;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.WindowManager; import android.view.WindowManager;
import com.keepassdroid.compat.BuildCompat; import com.kunzisoft.keepass.compat.BuildCompat;
/** /**
* Locking Hide Activity that sets FLAG_SECURE to prevent screenshots, and from * Locking Hide Activity that sets FLAG_SECURE to prevent screenshots, and from

View File

@@ -1,11 +1,11 @@
/* /*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. * Copyright 2018 Jeremy Jamet / Kunzisoft.
* *
* This file is part of KeePass DX. * This file is part of KeePass DX.
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -16,13 +16,21 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/package com.keepassdroid.intents; */
package com.kunzisoft.keepass.adapters;
public class Intents { import android.support.v7.widget.RecyclerView;
public static final String TIMEOUT = "com.keepassdroid.timeout"; import android.view.View;
import android.widget.ImageView;
public static final String COPY_USERNAME = "com.keepassdroid.copy_username"; import android.widget.TextView;
public static final String COPY_PASSWORD = "com.keepassdroid.copy_password";
public static final String OPEN_INTENTS_FILE_BROWSE = "org.openintents.action.PICK_FILE"; abstract class BasicViewHolder extends RecyclerView.ViewHolder {
View container;
ImageView icon;
TextView text;
BasicViewHolder(View itemView) {
super(itemView);
}
} }

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.adapters;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kunzisoft.keepass.R;
class EntryViewHolder extends BasicViewHolder {
EntryViewHolder(View itemView) {
super(itemView);
container = itemView.findViewById(R.id.entry_container);
icon = (ImageView) itemView.findViewById(R.id.entry_icon);
text = (TextView) itemView.findViewById(R.id.entry_text);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.adapters;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kunzisoft.keepass.R;
class GroupViewHolder extends BasicViewHolder {
GroupViewHolder(View itemView) {
super(itemView);
container = itemView.findViewById(R.id.group_container);
icon = (ImageView) itemView.findViewById(R.id.group_icon);
text = (TextView) itemView.findViewById(R.id.group_text);
}
}

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -16,9 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*
*/ */
package com.keepassdroid.adapters; package com.kunzisoft.keepass.adapters;
import android.content.Context; import android.content.Context;
import android.support.v7.util.SortedList; import android.support.v7.util.SortedList;
@@ -32,12 +31,12 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwNode;
import com.keepassdroid.settings.PreferencesUtil;
import com.keepassdroid.database.SortNodeEnum;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.PwNode;
import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.settings.PreferencesUtil;
public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> { public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
@@ -176,7 +175,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
public void onBindViewHolder(BasicViewHolder holder, int position) { public void onBindViewHolder(BasicViewHolder holder, int position) {
PwNode subNode = nodeSortedList.get(position); PwNode subNode = nodeSortedList.get(position);
// Assign image // Assign image
App.getDB().drawFactory.assignDrawableTo(holder.icon, App.getDB().getDrawFactory().assignDrawableTo(holder.icon,
context.getResources(), subNode.getIcon()); context.getResources(), subNode.getIcon());
// Assign text // Assign text
holder.text.setText(subNode.getDisplayTitle()); holder.text.setText(subNode.getDisplayTitle());
@@ -265,7 +264,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) { public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
MenuItem clearMenu = contextMenu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open); MenuItem clearMenu = contextMenu.add(Menu.NONE, MENU_OPEN, Menu.NONE, R.string.menu_open);
clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener); clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);
if (!App.getDB().readOnly && !node.equals(App.getDB().pm.getRecycleBin())) { if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
// TODO make edit for group // TODO make edit for group
// clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit); // clearMenu = contextMenu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.menu_edit);
// clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener); // clearMenu.setOnMenuItemClickListener(mOnMyActionClickListener);

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,14 +17,14 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.app; package com.kunzisoft.keepass.app;
import android.support.multidex.MultiDexApplication; import android.support.multidex.MultiDexApplication;
import com.keepassdroid.compat.PRNGFixes; import com.kunzisoft.keepass.compat.PRNGFixes;
import com.keepassdroid.database.Database; import com.kunzisoft.keepass.database.Database;
import com.keepassdroid.fileselect.RecentFileHistory; import com.kunzisoft.keepass.fileselect.RecentFileHistory;
import com.keepassdroid.stylish.Stylish; import com.kunzisoft.keepass.stylish.Stylish;
import java.util.Calendar; import java.util.Calendar;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.autofill; package com.kunzisoft.keepass.autofill;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.assist.AssistStructure; import android.app.assist.AssistStructure;
@@ -29,8 +29,8 @@ import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import com.keepassdroid.fileselect.FileSelectActivity;
import com.kunzisoft.keepass.KeePass; import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.fileselect.FileSelectActivity;
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
public class AutoFillAuthActivity extends KeePass { public class AutoFillAuthActivity extends KeePass {

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.autofill; package com.kunzisoft.keepass.autofill;
import android.app.Activity; import android.app.Activity;
import android.app.assist.AssistStructure; import android.app.assist.AssistStructure;
@@ -34,8 +34,8 @@ import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue; import android.view.autofill.AutofillValue;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import com.keepassdroid.database.PwEntry;
import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.database.PwEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.autofill; package com.kunzisoft.keepass.autofill;
import android.app.assist.AssistStructure; import android.app.assist.AssistStructure;
import android.content.IntentSender; import android.content.IntentSender;

View File

@@ -5,7 +5,7 @@
* *
* KeePass DX is free software: you can redistribute it and/or modify * KeePass DX 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
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* KeePass DX is distributed in the hope that it will be useful, * KeePass DX is distributed in the hope that it will be useful,
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.keepassdroid.autofill; package com.kunzisoft.keepass.autofill;
import android.app.assist.AssistStructure; import android.app.assist.AssistStructure;
import android.os.Build; import android.os.Build;

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