├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── Android-PwdHash.zip
├── ChangeLog
├── LICENSE
├── README.md
├── TODO
├── app
├── build.gradle
├── lint.xml
└── src
│ ├── androidTest
│ ├── java
│ │ └── com
│ │ │ └── uploadedlobster
│ │ │ └── PwdHash
│ │ │ ├── DomainExtractorTest.java
│ │ │ ├── HashedPasswordTest.java
│ │ │ ├── MainActivityTest.java
│ │ │ ├── PreferencesTest.java
│ │ │ └── utils
│ │ │ └── ToastMatcher.java
│ └── res
│ │ ├── drawable
│ │ └── icon.png
│ │ └── values
│ │ └── strings.xml
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── uploadedlobster
│ │ └── PwdHash
│ │ ├── activities
│ │ └── PwdHashApp.kt
│ │ ├── algorithm
│ │ ├── DomainExtractor.kt
│ │ └── HashedPassword.kt
│ │ ├── storage
│ │ ├── HistoryDataSource.kt
│ │ ├── HistoryOpenHelper.kt
│ │ └── UpdateHistoryTask.kt
│ │ └── util
│ │ ├── Constants.kt
│ │ └── Preferences.kt
│ └── res
│ ├── drawable-hdpi
│ └── icon.png
│ ├── drawable-ldpi
│ └── icon.png
│ ├── drawable-mdpi
│ └── icon.png
│ ├── drawable-xhdpi
│ └── icon.png
│ ├── drawable-xxhdpi
│ └── icon.png
│ ├── drawable-xxxhdpi
│ └── icon.png
│ ├── layout
│ └── main.xml
│ ├── values-ar
│ └── strings.xml
│ ├── values-ca
│ └── strings.xml
│ ├── values-cs
│ └── strings.xml
│ ├── values-de
│ └── strings.xml
│ ├── values-el
│ └── strings.xml
│ ├── values-es
│ └── strings.xml
│ ├── values-fr
│ └── strings.xml
│ ├── values-hr
│ └── strings.xml
│ ├── values-it
│ └── strings.xml
│ ├── values-ja
│ └── strings.xml
│ ├── values-ko
│ └── strings.xml
│ ├── values-nb-rNO
│ └── strings.xml
│ ├── values-nl-rNL
│ └── strings.xml
│ ├── values-pl
│ └── strings.xml
│ ├── values-pt-rBR
│ └── strings.xml
│ ├── values-ro-rRO
│ └── strings.xml
│ ├── values-ru
│ └── strings.xml
│ ├── values-tr
│ └── strings.xml
│ ├── values-uk
│ └── strings.xml
│ ├── values-v11
│ ├── style.xml
│ └── theme.xml
│ ├── values-v21
│ ├── geometry.xml
│ ├── style.xml
│ └── theme.xml
│ ├── values-vi
│ └── strings.xml
│ ├── values-zh-rCN
│ └── strings.xml
│ └── values
│ ├── geometry.xml
│ ├── strings.xml
│ ├── style.xml
│ └── theme.xml
├── build.gradle
├── design
├── feature-graphic.svg
└── icon.svg
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | Thumbs.db
9 | build/
10 | app/release/
11 | /captures
12 | .externalNativeBuild
13 | *~
14 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | xmlns:android
11 |
12 | ^$
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | xmlns:.*
22 |
23 | ^$
24 |
25 |
26 | BY_NAME
27 |
28 |
29 |
30 |
31 |
32 |
33 | .*:id
34 |
35 | http://schemas.android.com/apk/res/android
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | .*:name
45 |
46 | http://schemas.android.com/apk/res/android
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | name
56 |
57 | ^$
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | style
67 |
68 | ^$
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | .*
78 |
79 | ^$
80 |
81 |
82 | BY_NAME
83 |
84 |
85 |
86 |
87 |
88 |
89 | .*
90 |
91 | http://schemas.android.com/apk/res/android
92 |
93 |
94 | ANDROID_ATTRIBUTE_ORDER
95 |
96 |
97 |
98 |
99 |
100 |
101 | .*
102 |
103 | .*
104 |
105 |
106 | BY_NAME
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Android-PwdHash.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/Android-PwdHash.zip
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | 2019-09-27 Philipp Wolfer
2 | * Release 1.3.15
3 | * Tested with Android 9 and 10
4 | * Passwords should be invisible to the accessibility services (mohammadnaseri)
5 |
6 | 2018-05-03 Philipp Wolfer
7 | * Release 1.3.14
8 | * Tested with Android 8.1
9 | * Norwegian Bokmål translation (by Allan Nordhøy)
10 | * Italian translation
11 | * Use new clipboard API for Android API level >= 11
12 | * Disable personalized keyboard learning on password input, if supported (Pedro Veloso)
13 | * Migrated build to Android Studio
14 |
15 | 2015-04-16 Philipp Wolfer
16 |
17 | * Release 1.3.13
18 | * Greek translation (by Wasilis Mandratzis-Walz)
19 | * Ukrainian translation (by sorenabell)
20 | * Tested with Android 5.1
21 |
22 | 2014-11-05 Philipp Wolfer
23 |
24 | * Release 1.3.12
25 | * Fixed gradient in new app icon
26 |
27 | 2014-11-04 Philipp Wolfer
28 |
29 | * Release 1.3.11
30 | * Japanese translation (by Naofumi)
31 | * Updated Spanish translation
32 | * Tested with Android 5.0
33 | * Use Material theme on Android 5.0
34 | * Improved app icon
35 |
36 | 2014-04-11 Philipp Wolfer
37 |
38 | * Release 1.3.10
39 | * Setup Transifex synchronisation
40 | * Added Romanian translation (by ArianServ)
41 | * Added Turkish translation (by Muhammed İyi)
42 | * Updated French and Vietnamese translations
43 | * Partial Arabic translation
44 |
45 | 2013-12-27 Philipp Wolfer
46 |
47 | * Release 1.3.9
48 | * Added Croatian translation (by Marijan Smetko, Novska, Croatia)
49 | * Fixed another possible exception when launched from another app
50 | * Tested with Android 4.4
51 |
52 | 2013-09-09 Philipp Wolfer
53 |
54 | * Release 1.3.8
55 | * Fixed possible exception on start
56 |
57 | 2013-09-01 Philipp Wolfer
58 |
59 | * Release 1.3.7
60 | * Fixed occasional crash on some Android 4.3 devices
61 | * Dutch translation (by Kevin Morssink)
62 |
63 | 2013-07-25 Philipp Wolfer
64 |
65 | * Release 1.3.6
66 | * Keyboard should use no auto correction in URL input
67 | * Bugfix: Removed screenshot blocking in Android prior
68 | to 3.0. This security fix caused a distorted screen
69 | on some Samsung devices running Android 2.2 or 2.3.
70 | * Updated Czech translation
71 | * Tested with Android 4.3
72 |
73 | 2013-06-30 Philipp Wolfer
74 |
75 | * Release 1.3.5
76 | * French translation
77 | * Vietnamese translation (by Phan Anh)
78 |
79 | 2013-06-06 Philipp Wolfer
80 |
81 | * Release 1.3.4
82 | * Brazilian Portuguese translation (by Evandro)
83 | * Updated Korean translation (by Jongha Kim)
84 |
85 |
86 | 2013-05-18 Philipp Wolfer
87 |
88 | * Release 1.3.3
89 | * Korean translation (by Jongha Kim)
90 | * Czech translation (by Ondřej Vodáček)
91 |
92 | 2013-03-09 Philipp Wolfer
93 |
94 | * Release 1.3.2
95 | * Trim the URL to the domain part when "share" feature is used.
96 | * Use monospaced font for displaying the hashed password.
97 |
98 | 2012-11-07 Philipp Wolfer
99 |
100 | * Release 1.3.1
101 | * Security fix: Don't allow screenshots in recent apps menu
102 |
103 | 2012-07-09 Philipp Wolfer
104 |
105 | * Release 1.3.0
106 | * Auto completion for recently used domain names
107 | * Use Holo theme on Android 3.0 and newer
108 | * Added xhdpi icon
109 | * Enabled app on SD
110 | * Tested with Android 4.1 Jelly Bean
111 |
112 | 2012-05-18 Philipp Wolfer
113 |
114 | * Release 1.2.3
115 | * Remember last used site URL.
116 | * Added Chinese (China, simplified) translation.
117 |
118 | 2012-01-16 Philipp Wolfer
119 |
120 | * Release 1.2.2
121 | * Added Russian and Polish translations.
122 |
123 | 2011-09-28 Philipp Wolfer
124 |
125 | * Release 1.2.1
126 | * Added Spanish and Catalan translations.
127 |
128 | 2011-06-30 Philipp Wolfer
129 |
130 | * Release 1.2
131 | * Remove NULL bytes from end of hashed passwords (fixes issue #1)
132 | * Move all dimensions to resource file
133 |
134 | 2011-02-08 Philipp Wolfer
135 |
136 | * Release 1.1
137 | * Use density independent pixels
138 | * Set copy button inactive when unusable
139 | * Limit window width on large screens
140 |
141 | 2010-12-12 Philipp Wolfer
142 |
143 | * Initial release 1.0
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | PwdHash for Android is Copyright (c) 2010-2011 Philipp Wolfer
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions
5 | are met:
6 | 1. Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | 2. Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | 3. Neither the name of PwdHash for Android nor the names of the
12 | contributors may be used to endorse or promote products derived from
13 | this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android PwdHash
2 | ===============
3 |
4 | Description
5 | -----------
6 | Lightweight tool to generate website specific, theft-resistant passwords. Just
7 | use the "Share page" option in the Android browser or open Password Hash
8 | directly. Based upon and compatible with pwdhash.com.
9 |
10 | License
11 | -------
12 | Android PwdHash is free software published under a BSD style open source license.
13 | See LICENSE for details.
14 |
15 | Translations
16 | ------------
17 | You can help translate this project into your language. Please visit the Android PwdHash
18 | localization project on https://translate.uploadedlobster.com/engage/android-pwdhash/
19 |
20 | Known Issues
21 | -----------
22 | * Android PwdHash does not allow empty passwords for generating the hash, while
23 | pwdhash.com does.
24 |
25 | Author
26 | ------
27 | Philipp Wolfer
28 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | * Copy to clipboard and open browser
2 | * Allow cleartext password field
3 | * Better notify user about empty input (flash/animate the TextEdit)
4 | * Place Password Hash in notification area for quick access
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 31
6 | buildToolsVersion '30.0.3'
7 | defaultConfig {
8 | applicationId "com.uploadedlobster.PwdHash"
9 | minSdkVersion 17
10 | targetSdkVersion 31
11 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
12 | versionCode 26
13 | versionName '1.3.15'
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
19 | }
20 | }
21 | return void
22 | }
23 |
24 | dependencies {
25 | testImplementation 'junit:junit:4.13.2'
26 | androidTestImplementation 'androidx.annotation:annotation:1.2.0'
27 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
28 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
29 | implementation "androidx.core:core-ktx:1.6.0"
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31 | }
32 |
--------------------------------------------------------------------------------
/app/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/uploadedlobster/PwdHash/DomainExtractorTest.java:
--------------------------------------------------------------------------------
1 | package com.uploadedlobster.PwdHash;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 |
5 | import com.uploadedlobster.PwdHash.algorithm.DomainExtractor;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | import static org.junit.Assert.assertEquals;
15 |
16 | /**
17 | * @author Philipp Wolfer
18 | */
19 | @RunWith(AndroidJUnit4.class)
20 | public class DomainExtractorTest {
21 |
22 | private static HashMap testSamples;
23 |
24 | @Before
25 | public void setUp() throws Exception {
26 | testSamples = new HashMap<>();
27 | testSamples.put("example.com", "example.com");
28 | testSamples.put("http://example.com", "example.com");
29 | testSamples.put("http://example.com/aPath/test.html", "example.com");
30 | testSamples.put("http://www.example.com", "example.com");
31 | testSamples.put("https://www.example.com", "example.com");
32 | testSamples.put("http://www.example.com/aPath/test.html", "example.com");
33 | testSamples.put("http://login.test.example.com", "example.com");
34 | testSamples.put("http://example.co.uk", "example.co.uk");
35 | testSamples.put("http://login.example.co.uk", "example.co.uk");
36 | testSamples.put("https://login.example.co.uk/test.htm", "example.co.uk");
37 | }
38 |
39 | @Test
40 | public void testExtractDomain() throws Exception {
41 | for (Map.Entry t : testSamples.entrySet()) {
42 | assertEquals(t.getValue(),
43 | DomainExtractor.extractDomain(t.getKey()));
44 | }
45 | }
46 |
47 | @Test
48 | public void testExtractDomainWithEmptyStringInput() throws Exception {
49 | assertEquals("", DomainExtractor.extractDomain(""));
50 | }
51 |
52 | @Test(expected = IllegalArgumentException.class)
53 | public void testExtractDomainWithNullInput() throws Exception {
54 | DomainExtractor.extractDomain(null);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/uploadedlobster/PwdHash/HashedPasswordTest.java:
--------------------------------------------------------------------------------
1 | package com.uploadedlobster.PwdHash;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 |
5 | import com.uploadedlobster.PwdHash.algorithm.HashedPassword;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * @author Philipp Wolfer
14 | */
15 | @RunWith(AndroidJUnit4.class)
16 | public class HashedPasswordTest {
17 |
18 | @Test
19 | public void testToString() {
20 | HashedPassword hashedPassword = HashedPassword.create("my53cret#",
21 | "example.com");
22 | assertEquals("Bu6aSm+Zcsf", hashedPassword.toString());
23 | }
24 |
25 | @Test
26 | public void testToStringWithNonAsciiChars() {
27 | HashedPassword hashedPassword = HashedPassword.create("mü53crét#",
28 | "example.com");
29 | assertEquals("r9qeSjv+lwJ", hashedPassword.toString());
30 | }
31 |
32 | @Test
33 | public void testToStringWithNonLatin1Chars() {
34 | HashedPassword hashedPassword = HashedPassword.create("中文العربي",
35 | "example.com");
36 | assertEquals("AwMz3+BdMT", hashedPassword.toString());
37 | }
38 |
39 | @Test
40 | public void testToStringWithoutNonAlphanumeric() {
41 | HashedPassword hashedPassword = HashedPassword.create("my53cret",
42 | "example.com");
43 | assertEquals("CIUD4SCSgh", hashedPassword.toString());
44 | }
45 |
46 | @Test
47 | public void testToStringWithShortSecret() {
48 | HashedPassword hashedPassword = HashedPassword.create("ab",
49 | "example.com");
50 | assertEquals("0IKv", hashedPassword.toString());
51 | }
52 |
53 | @Test
54 | public void testToStringWithShortestSecret() {
55 | HashedPassword hashedPassword = HashedPassword.create("a",
56 | "example.com");
57 | assertEquals("9FBo", hashedPassword.toString());
58 | }
59 |
60 | @Test
61 | public void testToStringWithLongSecret() {
62 | HashedPassword hashedPassword = HashedPassword.create(
63 | "abcdefghijklmnopqrstuvwxyz0123456789=", "example.com");
64 | String result = hashedPassword.toString();
65 |
66 | // The original algorithm appends NULL bytes at the end.
67 | // Those bytes should not be part of the output.
68 | // "XO3u58jVa1nd+8qd08SDIQ\0\0\0\0"
69 | assertEquals("XO3u58jVa1nd+8qd08SDIQ", result);
70 | }
71 |
72 | @Test(expected = IllegalArgumentException.class)
73 | public void testToStringWithEmptySecret() {
74 | HashedPassword hashedPassword = HashedPassword.create("",
75 | "example.com");
76 | hashedPassword.toString();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/uploadedlobster/PwdHash/MainActivityTest.java:
--------------------------------------------------------------------------------
1 | package com.uploadedlobster.PwdHash;
2 |
3 | import android.content.ClipboardManager;
4 | import android.content.Context;
5 | import androidx.test.espresso.ViewInteraction;
6 | import androidx.test.rule.ActivityTestRule;
7 | import androidx.test.ext.junit.runners.AndroidJUnit4;
8 |
9 | import com.uploadedlobster.PwdHash.activities.PwdHashApp;
10 |
11 | import org.junit.Before;
12 | import org.junit.Rule;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 |
16 | import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
17 | import static androidx.test.platform.app.InstrumentationRegistry.getTargetContext;
18 | import static androidx.test.espresso.Espresso.onView;
19 | import static androidx.test.espresso.action.ViewActions.clearText;
20 | import static androidx.test.espresso.action.ViewActions.click;
21 | import static androidx.test.espresso.action.ViewActions.replaceText;
22 | import static androidx.test.espresso.action.ViewActions.typeText;
23 | import static androidx.test.espresso.assertion.ViewAssertions.matches;
24 | import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
25 | import static androidx.test.espresso.matcher.ViewMatchers.withId;
26 | import static androidx.test.espresso.matcher.ViewMatchers.withText;
27 | import static junit.framework.TestCase.assertEquals;
28 | import static org.hamcrest.CoreMatchers.not;
29 |
30 | /**
31 | * @author Philipp Wolfer
32 | */
33 | @RunWith(AndroidJUnit4.class)
34 | public class MainActivityTest {
35 | private ViewInteraction siteAddressInput;
36 | private ViewInteraction passwordInput;
37 | private ViewInteraction copyBtn;
38 |
39 | @Rule
40 | public ActivityTestRule mActivityRule = new ActivityTestRule<>(
41 | PwdHashApp.class);
42 |
43 | @Before
44 | public void setUp() throws Exception {
45 | siteAddressInput = onView(withId(R.id.siteAddress));
46 | passwordInput = onView(withId(R.id.password));
47 | copyBtn = onView(withId(R.id.copyBtn));
48 | }
49 |
50 | @Test
51 | public void testCopyButtonDisabledWhenAllInputsAreEmpty() {
52 | clearAllInputs();
53 | copyBtn.check(matches(not(isEnabled())));
54 | }
55 |
56 | @Test
57 | public void testCopyButtonEnabledWhenAllInputsAreSet() {
58 | clearAllInputs();
59 | siteAddressInput.perform(typeText("http://www.example.com/test"));
60 | passwordInput.perform(typeText("mysecret"));
61 | copyBtn.check(matches(isEnabled()));
62 | }
63 |
64 | @Test
65 | public void testCopyButtonDisabledWhenOnlySiteAdressInputIsSet() {
66 | clearAllInputs();
67 | siteAddressInput.perform(typeText("http://www.example.com/test"));
68 | copyBtn.check(matches(not(isEnabled())));
69 | }
70 |
71 | @Test
72 | public void testCopyButtonDisabledWhenOnlyPasswordInputIsSet() {
73 | clearAllInputs();
74 | passwordInput.perform(typeText("mysecret"));
75 | copyBtn.check(matches(not(isEnabled())));
76 | }
77 |
78 | @Test
79 | public void testCopyToClipboard() {
80 | clearAllInputs();
81 | siteAddressInput.perform(typeText("http://www.example.com/test"));
82 | passwordInput.perform(typeText("mysecret"));
83 | copyBtn.perform(click());
84 |
85 | getInstrumentation().runOnMainSync(new Runnable() {
86 | @SuppressWarnings("deprecation")
87 | @Override
88 | public void run() {
89 | final Context context = getTargetContext();
90 | String clipboardContent;
91 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
92 | final ClipboardManager clipboard = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
93 | clipboardContent = clipboard.getPrimaryClip().getItemAt(0).getText().toString();
94 | }
95 | else {
96 | final android.text.ClipboardManager clipboard = (android.text.ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
97 | clipboardContent = clipboard.getText().toString();
98 | }
99 |
100 | assertEquals("C3bvEXk6rU", clipboardContent);
101 | }
102 | });
103 | }
104 |
105 | // @Test
106 | // public void testToastMessage() {
107 | // clearAllInputs();
108 | //
109 | // siteAddressInput.perform(typeText("http://www.example.com/test"));
110 | // passwordInput.perform(typeText("mysecret"));
111 | // copyBtn.perform(click());
112 | //
113 | // // Check display of toast message
114 | // onView(withText(R.string.copiedToClipboardNotification))
115 | // .inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView())))
116 | // .check(matches(isDisplayed()));
117 | // onView(withText(R.string.copiedToClipboardNotification)).inRoot(new ToastMatcher())
118 | // .check(matches(isDisplayed()));
119 | // }
120 |
121 | @Test
122 | public void testDisplayOfPassword() {
123 | ViewInteraction hashedPassword = onView(withId(R.id.hashedPassword));
124 | hashedPassword.check(matches(not(withText("C3bvEXk6rU"))));
125 |
126 | clearAllInputs();
127 | siteAddressInput.perform(typeText("http://www.example.com/test"));
128 | passwordInput.perform(typeText("mysecret"));
129 | hashedPassword.check(matches(withText("C3bvEXk6rU")));
130 |
131 | passwordInput.perform(replaceText("myothersecret"));
132 | hashedPassword.check(matches(not(withText("C3bvEXk6rU"))));
133 | hashedPassword.check(matches(withText("dG4KvuJTNGrWRY2")));
134 | }
135 |
136 | private void clearAllInputs() {
137 | siteAddressInput.perform(clearText());
138 | passwordInput.perform(clearText());
139 | }
140 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/uploadedlobster/PwdHash/PreferencesTest.java:
--------------------------------------------------------------------------------
1 | package com.uploadedlobster.PwdHash;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import com.uploadedlobster.PwdHash.util.Preferences;
8 |
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 |
12 | import static org.junit.Assert.assertEquals;
13 | import static org.junit.Assert.assertNotEquals;
14 |
15 | @RunWith(AndroidJUnit4.class)
16 | public class PreferencesTest {
17 | @Test
18 | public void testSaveSiteAddress() {
19 | final Context context = InstrumentationRegistry.getTargetContext();
20 | Preferences preferences = new Preferences(context);
21 |
22 | String urlToSave = "https://www.example.com/storage-test";
23 | String urlLoaded = preferences.getSavedSiteAddress();
24 |
25 | assertNotEquals(urlToSave, urlLoaded);
26 |
27 | preferences.setSavedSiteAddress(urlToSave);
28 | urlLoaded = preferences.getSavedSiteAddress();
29 | assertEquals(urlToSave, urlLoaded);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/uploadedlobster/PwdHash/utils/ToastMatcher.java:
--------------------------------------------------------------------------------
1 | package com.uploadedlobster.PwdHash.utils;
2 |
3 | import android.os.IBinder;
4 | import androidx.test.espresso.Root;
5 | import android.view.WindowManager;
6 |
7 | import org.hamcrest.Description;
8 | import org.hamcrest.TypeSafeMatcher;
9 |
10 | class ToastMatcher extends TypeSafeMatcher {
11 |
12 | @Override
13 | public void describeTo(Description description) {
14 | description.appendText("is toast");
15 | }
16 |
17 | @Override
18 | public boolean matchesSafely(Root root) {
19 | int type = root.getWindowLayoutParams().get().type;
20 | if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
21 | IBinder windowToken = root.getDecorView().getWindowToken();
22 | IBinder appToken = root.getDecorView().getApplicationWindowToken();
23 | if (windowToken == appToken) {
24 | //means this window isn't contained by any other windows.
25 | return true;
26 | }
27 | }
28 | return false;
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/androidTest/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/androidTest/res/drawable/icon.png
--------------------------------------------------------------------------------
/app/src/androidTest/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password HashTest
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/activities/PwdHashApp.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, PwdHashApp.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2010 - 2013 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.activities
34 |
35 | import android.app.Activity
36 | import android.content.ClipData
37 | import android.content.ClipboardManager
38 | import android.content.Intent
39 | import android.database.Cursor
40 | import android.os.Bundle
41 | import android.text.Editable
42 | import android.text.TextWatcher
43 | import android.util.DisplayMetrics
44 | import android.util.Log
45 | import android.view.View
46 | import android.view.WindowManager
47 | import android.widget.*
48 | import android.widget.SimpleCursorAdapter.CursorToStringConverter
49 | import com.uploadedlobster.PwdHash.R
50 | import com.uploadedlobster.PwdHash.algorithm.DomainExtractor.extractDomain
51 | import com.uploadedlobster.PwdHash.algorithm.HashedPassword.Companion.create
52 | import com.uploadedlobster.PwdHash.storage.HistoryDataSource
53 | import com.uploadedlobster.PwdHash.storage.HistoryOpenHelper
54 | import com.uploadedlobster.PwdHash.storage.UpdateHistoryTask
55 | import com.uploadedlobster.PwdHash.util.Preferences
56 |
57 | /**
58 | * @author Philipp Wolfer @gmail.com>
59 | */
60 | class PwdHashApp : Activity() {
61 | private var mPreferences: Preferences? = null
62 | private var mHistory: HistoryDataSource? = null
63 | private var mSiteAddress: AutoCompleteTextView? = null
64 | private var mPassword: EditText? = null
65 | private var mHashedPassword: TextView? = null
66 | private var mCopyBtn: Button? = null
67 | private var mSaveStateOnExit = true
68 |
69 | /** Called when the activity is first created. */
70 | public override fun onCreate(savedInstanceState: Bundle?) {
71 | super.onCreate(savedInstanceState)
72 | window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
73 | setContentView(R.layout.main)
74 | mSiteAddress = findViewById(R.id.siteAddress) as AutoCompleteTextView
75 | mPassword = findViewById(R.id.password) as EditText
76 | mHashedPassword = findViewById(R.id.hashedPassword) as TextView
77 | mCopyBtn = findViewById(R.id.copyBtn) as Button
78 | mPreferences = Preferences(this)
79 | mHistory = HistoryDataSource(this)
80 | setWindowGeometry()
81 | restoreSavedState()
82 | handleIntents()
83 | registerEventListeners()
84 | initAutoComplete()
85 | }
86 |
87 | override fun onStop() {
88 | super.onStop()
89 | if (mSaveStateOnExit) {
90 | mPreferences!!.savedSiteAddress = domain
91 | } else {
92 | mPreferences!!.savedSiteAddress = ""
93 | }
94 | }
95 |
96 | private fun setWindowGeometry() {
97 | val window = window
98 | window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT)
99 | val metrics = DisplayMetrics()
100 | windowManager.defaultDisplay.getMetrics(metrics)
101 | val maxWidth = resources.getDimensionPixelSize(
102 | R.dimen.maxWindowWidth)
103 | if (metrics.widthPixels > maxWidth) {
104 | window.setLayout(maxWidth, WindowManager.LayoutParams.WRAP_CONTENT)
105 | }
106 | }
107 |
108 | private fun restoreSavedState() {
109 | val savedSiteAddress = mPreferences!!.savedSiteAddress
110 | if (savedSiteAddress != "") {
111 | mSiteAddress!!.setText(savedSiteAddress)
112 | }
113 | }
114 |
115 | private fun handleIntents() {
116 | val intent = intent
117 | if (intent != null) {
118 | val action = intent.action
119 | if (action != null && action == Intent.ACTION_SEND) {
120 | var siteAddress = intent.getStringExtra(Intent.EXTRA_TEXT)
121 | if (siteAddress != null && siteAddress != "") {
122 | siteAddress = extractDomain(siteAddress)
123 | mSiteAddress!!.setText(siteAddress)
124 | mPassword!!.requestFocus()
125 | }
126 | }
127 | }
128 | }
129 |
130 | private fun initAutoComplete() {
131 | mHistory!!.open()
132 | val from = arrayOf(HistoryOpenHelper.COLUMN_REALM)
133 | val to = intArrayOf(android.R.id.text1)
134 | val adapter = SimpleCursorAdapter(this,
135 | android.R.layout.simple_dropdown_item_1line, null, from, to, 0)
136 |
137 | // Set the CursorToStringConverter, to provide the labels for the
138 | // choices to be displayed in the AutoCompleteTextView.
139 | adapter.cursorToStringConverter = CursorToStringConverter { cursor: Cursor ->
140 | val columnIndex = cursor.getColumnIndexOrThrow(HistoryOpenHelper.COLUMN_REALM)
141 | cursor.getString(columnIndex)
142 | }
143 |
144 | // Set the FilterQueryProvider, to run queries for choices
145 | // that match the specified input.
146 | adapter.filterQueryProvider = FilterQueryProvider { constraint ->
147 | val partialInput = constraint?.toString() ?: ""
148 | mHistory!!.getHistoryCursor(partialInput)
149 | }
150 | mSiteAddress!!.setAdapter(adapter)
151 | }
152 |
153 | private fun registerEventListeners() {
154 | val updatePasswordTextWatcher: TextWatcher = object : TextWatcher {
155 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
156 | val realm = domain
157 | val password = mPassword!!.text.toString()
158 | updateHashedPassword(realm, password)
159 | }
160 |
161 | override fun beforeTextChanged(
162 | s: CharSequence, start: Int, count: Int,
163 | after: Int
164 | ) {
165 | }
166 |
167 | override fun afterTextChanged(s: Editable) {}
168 | }
169 | mSiteAddress!!.addTextChangedListener(updatePasswordTextWatcher)
170 | mPassword!!.addTextChangedListener(updatePasswordTextWatcher)
171 | mCopyBtn!!.setOnClickListener {
172 | val realm = domain
173 | val password = mPassword!!.text.toString()
174 | if (realm == "") {
175 | mSiteAddress!!.requestFocus()
176 | } else if (password == "") {
177 | mPassword!!.requestFocus()
178 | } else {
179 | val hashedPassword = updateHashedPassword(realm, password)
180 | if (hashedPassword != "") {
181 | UpdateHistoryTask(mHistory!!).execute(realm)
182 | copyToClipboard(hashedPassword)
183 | val clipboardNotification: CharSequence =
184 | getString(R.string.copiedToClipboardNotification)
185 | showNotification(clipboardNotification)
186 | mSaveStateOnExit = false
187 | finish()
188 | }
189 | }
190 | }
191 | }
192 |
193 | private val domain: String get() = extractDomain(mSiteAddress!!.text.toString())
194 |
195 | private fun updateHashedPassword(realm: String, password: String): String {
196 | var result = ""
197 | if (realm != "" && password != "") {
198 | val hashedPassword = create(password, realm)
199 | result = hashedPassword.toString()
200 | }
201 | mCopyBtn!!.isEnabled = result != ""
202 | mHashedPassword!!.text = result
203 | return result
204 | }
205 |
206 | private fun showNotification(text: CharSequence) {
207 | val duration = Toast.LENGTH_LONG
208 | val toast = Toast.makeText(this, text, duration)
209 | toast.show()
210 | }
211 |
212 | private fun copyToClipboard(hashedPassword: String) {
213 | try {
214 | val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
215 | val clip = ClipData.newPlainText("", hashedPassword)
216 | clipboard.setPrimaryClip(clip)
217 | } catch (e: IllegalStateException) {
218 | // Workaround for some Android 4.3 devices, where writing to the clipboard manager raises an exception
219 | // if there is an active clipboard listener.
220 | Log.w("PwdHashApp", "IllegalStateException raised when accessing clipboard.")
221 | }
222 | }
223 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/algorithm/DomainExtractor.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, DomainExtractor.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2010 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.algorithm
34 |
35 | /**
36 | * Domain name extractor.
37 | *
38 | * Turns host names into domain names. Based on original JavaScript code from:
39 | * https://www.pwdhash.com/
40 | *
41 | * @author Philipp Wolfer @gmail.com>
42 | */
43 | object DomainExtractor {
44 | @JvmStatic
45 | @Throws(IllegalArgumentException::class)
46 | fun extractDomain(uri: String?): String {
47 | requireNotNull(uri) { "Argument uri must not be null." }
48 | var domain: String = uri
49 | domain = domain.replace("http://", "")
50 | domain = domain.replace("https://", "")
51 | var firstSlash: Int
52 | if (domain.indexOf("/").also { firstSlash = it } > -1) domain =
53 | domain.substring(0, firstSlash)
54 | val parts = domain.split("\\.".toRegex()).toTypedArray()
55 | if (parts.size > 2) {
56 | domain = parts[parts.size - 2] + "." + parts[parts.size - 1]
57 | for (sld in mSecondLevelDomains) {
58 | if (domain == sld) domain = parts[parts.size - 3] + "." + domain
59 | }
60 | }
61 | return domain
62 | }
63 |
64 | private val mSecondLevelDomains = arrayOf("ab.ca", "ac.ac", "ac.at",
65 | "ac.be", "ac.cn", "ac.il", "ac.in", "ac.jp", "ac.kr", "ac.nz",
66 | "ac.th", "ac.uk", "ac.za", "adm.br", "adv.br", "agro.pl", "ah.cn",
67 | "aid.pl", "alt.za", "am.br", "arq.br", "art.br", "arts.ro",
68 | "asn.au", "asso.fr", "asso.mc", "atm.pl", "auto.pl", "bbs.tr",
69 | "bc.ca", "bio.br", "biz.pl", "bj.cn", "br.com", "cn.com", "cng.br",
70 | "cnt.br", "co.ac", "co.at", "co.il", "co.in", "co.jp", "co.kr",
71 | "co.nz", "co.th", "co.uk", "co.za", "com.au", "com.br", "com.cn",
72 | "com.ec", "com.fr", "com.hk", "com.mm", "com.mx", "com.pl",
73 | "com.ro", "com.ru", "com.sg", "com.tr", "com.tw", "cq.cn",
74 | "cri.nz", "de.com", "ecn.br", "edu.au", "edu.cn", "edu.hk",
75 | "edu.mm", "edu.mx", "edu.pl", "edu.tr", "edu.za", "eng.br",
76 | "ernet.in", "esp.br", "etc.br", "eti.br", "eu.com", "eu.lv",
77 | "fin.ec", "firm.ro", "fm.br", "fot.br", "fst.br", "g12.br",
78 | "gb.com", "gb.net", "gd.cn", "gen.nz", "gmina.pl", "go.jp",
79 | "go.kr", "go.th", "gob.mx", "gov.br", "gov.cn", "gov.ec", "gov.il",
80 | "gov.in", "gov.mm", "gov.mx", "gov.sg", "gov.tr", "gov.za",
81 | "govt.nz", "gs.cn", "gsm.pl", "gv.ac", "gv.at", "gx.cn", "gz.cn",
82 | "hb.cn", "he.cn", "hi.cn", "hk.cn", "hl.cn", "hn.cn", "hu.com",
83 | "idv.tw", "ind.br", "inf.br", "info.pl", "info.ro", "iwi.nz",
84 | "jl.cn", "jor.br", "jpn.com", "js.cn", "k12.il", "k12.tr",
85 | "lel.br", "ln.cn", "ltd.uk", "mail.pl", "maori.nz", "mb.ca",
86 | "me.uk", "med.br", "med.ec", "media.pl", "mi.th", "miasta.pl",
87 | "mil.br", "mil.ec", "mil.nz", "mil.pl", "mil.tr", "mil.za",
88 | "mo.cn", "muni.il", "nb.ca", "ne.jp", "ne.kr", "net.au", "net.br",
89 | "net.cn", "net.ec", "net.hk", "net.il", "net.in", "net.mm",
90 | "net.mx", "net.nz", "net.pl", "net.ru", "net.sg", "net.th",
91 | "net.tr", "net.tw", "net.za", "nf.ca", "ngo.za", "nm.cn", "nm.kr",
92 | "no.com", "nom.br", "nom.pl", "nom.ro", "nom.za", "ns.ca", "nt.ca",
93 | "nt.ro", "ntr.br", "nx.cn", "odo.br", "on.ca", "or.ac", "or.at",
94 | "or.jp", "or.kr", "or.th", "org.au", "org.br", "org.cn", "org.ec",
95 | "org.hk", "org.il", "org.mm", "org.mx", "org.nz", "org.pl",
96 | "org.ro", "org.ru", "org.sg", "org.tr", "org.tw", "org.uk",
97 | "org.za", "pc.pl", "pe.ca", "plc.uk", "ppg.br", "presse.fr",
98 | "priv.pl", "pro.br", "psc.br", "psi.br", "qc.ca", "qc.com",
99 | "qh.cn", "re.kr", "realestate.pl", "rec.br", "rec.ro", "rel.pl",
100 | "res.in", "ru.com", "sa.com", "sc.cn", "school.nz", "school.za",
101 | "se.com", "se.net", "sh.cn", "shop.pl", "sk.ca", "sklep.pl",
102 | "slg.br", "sn.cn", "sos.pl", "store.ro", "targi.pl", "tj.cn",
103 | "tm.fr", "tm.mc", "tm.pl", "tm.ro", "tm.za", "tmp.br",
104 | "tourism.pl", "travel.pl", "tur.br", "turystyka.pl", "tv.br",
105 | "tw.cn", "uk.co", "uk.com", "uk.net", "us.com", "uy.com", "vet.br",
106 | "web.za", "web.com", "www.ro", "xj.cn", "xz.cn", "yk.ca", "yn.cn",
107 | "za.com")
108 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/algorithm/HashedPassword.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, HashedPassword.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2010 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.algorithm
34 |
35 | import android.util.Base64
36 | import android.util.Log
37 | import java.io.UnsupportedEncodingException
38 | import java.security.InvalidKeyException
39 | import java.security.Key
40 | import java.security.NoSuchAlgorithmException
41 | import java.util.*
42 | import java.util.regex.Pattern
43 | import javax.crypto.Mac
44 | import javax.crypto.spec.SecretKeySpec
45 |
46 | /**
47 | * Hashed Password
48 | *
49 | * Combination of page URI and plain text password. Treated as a string, it is
50 | * the hashed password. Based on original JavaScript code from:
51 | * https://www.pwdhash.com/
52 | *
53 | * @author Philipp Wolfer @gmail.com>
54 | */
55 | class HashedPassword private constructor(
56 | private val mPassword: String,
57 | private val mRealm: String
58 | ) {
59 | private var mHash: String? = null
60 | private var mExtras: Queue? = null
61 | override fun toString(): String {
62 | return mHash!!
63 | }
64 |
65 | private fun calculateHash() {
66 | val md5 = createHmacMD5(mPassword, mRealm)
67 | val hash = Base64.encodeToString(md5, Base64.NO_PADDING
68 | or Base64.NO_WRAP)
69 | val size = mPassword.length + PasswordPrefix.length
70 | val nonAlphanumeric = NonAlphanumericMatcher.matcher(mPassword)
71 | .find()
72 | mHash = applyConstraints(hash, size, nonAlphanumeric)
73 | }
74 |
75 | private fun applyConstraints(
76 | hash: String, size: Int,
77 | nonAlphanumeric: Boolean
78 | ): String {
79 | var startingSize = size - 4
80 | if (startingSize < 0) startingSize = 0 else if (startingSize > hash.length) startingSize =
81 | hash.length
82 | var result = hash.substring(0, startingSize)
83 | mExtras = LinkedList()
84 | for (c in hash.substring(startingSize).toCharArray()) {
85 | mExtras!!.add(c)
86 | }
87 |
88 | // Add the extra characters
89 | result += if (Pattern.compile("[A-Z]").matcher(result)
90 | .find()
91 | ) nextExtraChar() else nextBetween('A', 26)
92 | result += if (Pattern.compile("[a-z]").matcher(result)
93 | .find()
94 | ) nextExtraChar() else nextBetween('a', 26)
95 | result += if (Pattern.compile("[0-9]").matcher(result)
96 | .find()
97 | ) nextExtraChar() else nextBetween('0', 10)
98 | result += if (NonAlphanumericMatcher.matcher(result).find()
99 | && nonAlphanumeric
100 | ) nextExtraChar() else '+'
101 | while (NonAlphanumericMatcher.matcher(result).find()
102 | && !nonAlphanumeric
103 | ) {
104 | val replacement = Character.toString(nextBetween('A', 26))
105 | result = NonAlphanumericMatcher.matcher(result).replaceFirst(
106 | replacement)
107 | }
108 |
109 | // For long passwords (about > 22 chars) the password might be longer
110 | // than the hash and mExtras is empty. In that case the constraints
111 | // above produce 0 bytes at the end of result. If nonAlphanumeric is not
112 | // set those 0 bytes are replaced, but in other cases they stay around
113 | // and must be removed here. This is a flaw in the original algorithm
114 | // which we have to work around here.
115 | result = result.replace("\u0000", "")
116 |
117 | // Rotate the result to make it harder to guess the inserted locations
118 | return rotate(result, nextExtra())
119 | }
120 |
121 | private fun nextExtra(): Int {
122 | return nextExtraChar().toInt()
123 | }
124 |
125 | private fun nextExtraChar(): Char {
126 | return if (mExtras!!.size > 0) mExtras!!.remove() else '0'
127 | }
128 |
129 | private fun nextBetween(base: Char, interval: Int): Char {
130 | return between(base.toInt(), interval, nextExtra()).toChar()
131 | }
132 |
133 | companion object {
134 | private const val HMAC_MD5 = "HmacMD5"
135 | private const val PasswordPrefix = "@@"
136 |
137 | /**
138 | * Pattern to match only word characters. Since Java's regex implementation
139 | * is unicode aware, the pattern \W would match also non-ASCII word
140 | * characters. But since the JavaScript implementation of PwdHash only
141 | * considers ASCII characters we stay compatible.
142 | */
143 | private val NonAlphanumericMatcher = Pattern
144 | .compile("[^a-zA-Z0-9_]")
145 |
146 | @JvmStatic
147 | fun create(password: String, realm: String): HashedPassword {
148 | val result = HashedPassword(password, realm)
149 | result.calculateHash()
150 | return result
151 | }
152 |
153 | private fun createHmacMD5(key: String?, data: String?): ByteArray {
154 | require(!(key == null || key == "")) { "key must not be null or empty" }
155 | requireNotNull(data) { "data must not be null" }
156 | val keyBytes = encodeStringToBytes(key)
157 | val dataBytes = encodeStringToBytes(data)
158 | return try {
159 | val mac = Mac.getInstance(HMAC_MD5)
160 | val sk: Key = SecretKeySpec(keyBytes, HMAC_MD5)
161 | mac.init(sk)
162 | mac.doFinal(dataBytes)
163 | } catch (e: NoSuchAlgorithmException) {
164 | Log.e(HashedPassword::class.java.name,
165 | "HMAC_MD5 algorithm not supported on this platform.", e)
166 | ByteArray(0)
167 | } catch (e: InvalidKeyException) {
168 | Log.e(HashedPassword::class.java.name, "Invalid secret key.", e)
169 | ByteArray(0)
170 | }
171 | }
172 |
173 | /**
174 | * Returns a new byte array with the encoded input string (1 byte per
175 | * character).
176 | *
177 | * Characters in the Latin 1 range (up to code point 255) will be returned
178 | * as Latin 1 encoded bytes. Characters above code point 255 will be
179 | * UTF-16le encoded but only the first byte will be used.
180 | *
181 | * This matches the original behavior of the PwdHash JavaScript
182 | * implementation pwdhash.com and keeps the hash values of passwords
183 | * containing non-latin1 characters compatible.
184 | *
185 | * @param data Input string
186 | * @return Byte array.
187 | */
188 | private fun encodeStringToBytes(data: String): ByteArray {
189 | val bytes = ByteArray(data.length)
190 | for (i in 0 until data.length) {
191 | val codePoint = data.codePointAt(i)
192 | if (codePoint <= 255) bytes[i] = codePoint.toByte() else {
193 | try {
194 | val nonLatin1Char = Character.toString(data[i])
195 | val charBytes = nonLatin1Char.toByteArray(charset("UTF-16le"))
196 | val unsignedByte = (0x000000FF and charBytes[0]
197 | .toInt()).toShort()
198 | bytes[i] = unsignedByte.toByte()
199 | } catch (e: UnsupportedEncodingException) {
200 | Log.w("Decoding error", Character.toString(data[i])
201 | + " could not be decoded as UTF-16le")
202 | bytes[i] = 0x1A // SUB
203 | }
204 | }
205 | }
206 | return bytes
207 | }
208 |
209 | private fun between(min: Int, interval: Int, offset: Int): Int {
210 | return min + offset % interval
211 | }
212 |
213 | private fun rotate(s: String, amount: Int): String {
214 | var amount = amount
215 | val work: Queue = LinkedList()
216 | for (c in s.toCharArray()) {
217 | work.add(c)
218 | }
219 | while (amount-- > 0) work.add(work.remove())
220 | val b = StringBuilder(work.size)
221 | for (c in work) b.append(c)
222 | return b.toString()
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/storage/HistoryDataSource.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, HistoryStorage.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2012 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.storage
34 |
35 | import android.content.Context
36 | import android.database.Cursor
37 | import android.database.SQLException
38 | import android.database.sqlite.SQLiteDatabase
39 |
40 | class HistoryDataSource(context: Context?) {
41 | private var mDatabase: SQLiteDatabase? = null
42 | private val mDbHelper: HistoryOpenHelper = HistoryOpenHelper(context)
43 |
44 | @Throws(SQLException::class)
45 | fun open() {
46 | mDatabase = mDbHelper.writableDatabase
47 | }
48 |
49 | fun close() {
50 | mDbHelper.close()
51 | }
52 |
53 | fun insertHistoryEntry(realm: String) {
54 | val id = getExistingEntryId(realm)
55 | val values = arrayOf(
56 | if (id < 0) null else id.toString(),
57 | realm, realm)
58 | val sql = ("INSERT OR REPLACE INTO history ("
59 | + HistoryOpenHelper.Companion.COLUMN_ID + ", "
60 | + HistoryOpenHelper.Companion.COLUMN_REALM + ", "
61 | + HistoryOpenHelper.Companion.COLUMN_USAGE_COUNT + ", "
62 | + HistoryOpenHelper.Companion.COLUMN_LAST_ACCESS + ") "
63 | + "VALUES (?, ?, "
64 | + "(SELECT "
65 | + HistoryOpenHelper.Companion.COLUMN_USAGE_COUNT
66 | + " + 1 FROM history WHERE "
67 | + HistoryOpenHelper.Companion.COLUMN_REALM
68 | + " = ?), datetime('now'))")
69 | mDatabase!!.execSQL(sql, values)
70 | }
71 |
72 | fun getHistoryCursor(partialRealm: String): Cursor {
73 | val columns = arrayOf(HistoryOpenHelper.Companion.COLUMN_ID,
74 | HistoryOpenHelper.COLUMN_REALM)
75 | val selection: String = HistoryOpenHelper.Companion.COLUMN_REALM + " LIKE ?"
76 | val selectionArgs = arrayOf("%$partialRealm%")
77 | val orderBy: String = (HistoryOpenHelper.Companion.COLUMN_USAGE_COUNT
78 | + " DESC, "
79 | + HistoryOpenHelper.Companion.COLUMN_LAST_ACCESS
80 | + " DESC")
81 | val limit = SUGGESTION_LIMIT.toString()
82 | return mDatabase!!.query(
83 | HistoryOpenHelper.Companion.TABLE_HISTORY,
84 | columns,
85 | selection,
86 | selectionArgs,
87 | "", "",
88 | orderBy,
89 | limit)
90 | }
91 |
92 | private fun getExistingEntryId(realm: String): Int {
93 | val columns = arrayOf(HistoryOpenHelper.Companion.COLUMN_ID)
94 | val selection: String = HistoryOpenHelper.Companion.COLUMN_REALM + " LIKE ?"
95 | val selectionArgs = arrayOf(realm)
96 | val cursor = mDatabase!!.query(HistoryOpenHelper.Companion.TABLE_HISTORY,
97 | columns,
98 | selection,
99 | selectionArgs,
100 | "",
101 | "",
102 | "")
103 | return if (cursor.moveToFirst()) {
104 | val idColumn = cursor.getColumnIndex(HistoryOpenHelper.Companion.COLUMN_ID)
105 | val id = cursor.getInt(idColumn)
106 | cursor.close()
107 | id
108 | } else {
109 | -1
110 | }
111 | }
112 |
113 | companion object {
114 | private const val SUGGESTION_LIMIT = 6
115 | }
116 |
117 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/storage/HistoryOpenHelper.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, HistoryOpenHelper.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2012 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.storage
34 |
35 | import android.content.Context
36 | import android.database.sqlite.SQLiteDatabase
37 | import android.database.sqlite.SQLiteOpenHelper
38 | import com.uploadedlobster.PwdHash.util.Constants
39 |
40 | class HistoryOpenHelper internal constructor(context: Context?) :
41 | SQLiteOpenHelper(context, Constants.DATABASE_NAME, null, Constants.DATABASE_VERSION) {
42 | override fun onCreate(db: SQLiteDatabase) {
43 | db.execSQL(CREATE_TABLE)
44 | }
45 |
46 | override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}
47 |
48 | companion object {
49 | const val TABLE_HISTORY = "history"
50 | const val COLUMN_ID = "_id"
51 | const val COLUMN_REALM = "realm"
52 | const val COLUMN_USAGE_COUNT = "usage_count"
53 | const val COLUMN_LAST_ACCESS = "last_access"
54 | private const val CREATE_TABLE = "CREATE TABLE " + TABLE_HISTORY + " (" +
55 | COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
56 | COLUMN_REALM + " TEXT," +
57 | COLUMN_USAGE_COUNT + " INTEGER NOT NULL DEFAULT 0," +
58 | COLUMN_LAST_ACCESS + " TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP)"
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/storage/UpdateHistoryTask.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, UpdateHistoryTask.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2012 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.storage
34 |
35 | import android.os.AsyncTask
36 |
37 | class UpdateHistoryTask(private val mDataSource: HistoryDataSource) :
38 | AsyncTask() {
39 | override fun doInBackground(vararg params: String?): Void? {
40 | for (realm in params) {
41 | if (realm != null) {
42 | mDataSource.insertHistoryEntry(realm)
43 | }
44 | }
45 | return null
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/util/Constants.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, Constants.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2012 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.util
34 |
35 | object Constants {
36 | const val PREFERENCES_NAME = "com.uploadedlobster.pwdhash.preferences"
37 | const val PREFERENCE_SAVED_SITE_ADDRESS = "saved_uri"
38 | const val DATABASE_NAME = "pwdhash"
39 | const val DATABASE_VERSION = 1
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/uploadedlobster/PwdHash/util/Preferences.kt:
--------------------------------------------------------------------------------
1 | /**
2 | * PwdHash, Preferences.java
3 | * A password hash implementation for Android.
4 | *
5 | * Copyright (c) 2012 Philipp Wolfer
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of the RBrainz project nor the names of the
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | * @author Philipp Wolfer @gmail.com>
32 | */
33 | package com.uploadedlobster.PwdHash.util
34 |
35 | import android.content.Context
36 | import android.content.SharedPreferences
37 |
38 | class Preferences(packageContext: Context) {
39 | private val mSettings: SharedPreferences = packageContext.getSharedPreferences(Constants.PREFERENCES_NAME, Context.MODE_PRIVATE)
40 |
41 | var savedSiteAddress: String?
42 | get() = mSettings.getString(Constants.PREFERENCE_SAVED_SITE_ADDRESS, "")
43 | set(siteAddress) {
44 | val editor = mSettings.edit()
45 | editor.putString(Constants.PREFERENCE_SAVED_SITE_ADDRESS, siteAddress)
46 | editor.apply()
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/app/src/main/res/drawable-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
18 |
19 |
26 |
27 |
32 |
33 |
40 |
41 |
46 |
47 |
53 |
54 |
60 |
61 |
62 |
67 |
68 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Site address
5 | http://example.com
6 | كلمة المرور
7 | Hash:
8 | نسخ
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Aplicació per generar contrasenyes segures per llocs web. Feu servir \"Compartir\" al vostre navegador Android o obriu Password Hash directament. Compatible amb pwdhash.com.
5 |
6 | Aplicación es distribueix lliurement sota llicencia open source.
7 | Lloc web
8 | http://example.com
9 | Password
10 | Hash:
11 | Copiar
12 | Contrasenya copiada al portapapers
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Jednoduchý nástroj pro generování hesel odolných proti krádeži. Stačí použít možnost „Sdílet stránku“ v Android prohlížeči nebo přímo otevřít Password Hash. Kompatibilní s psdhash.com.
5 |
6 | Tato aplikace je svobodný software publikovaný pod open source licencí.
7 | Adresa stránky
8 | http://example.com
9 | Heslo
10 | Hash:
11 | Zkopírovat
12 | Heslo bylo zkopírováno do schránky
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Leichtgewichtiges Tool zum Erzeugen von diebstahlsicheren Passwörtern. Password Hash kann einfach über die \"Seitenlink weiterleiten\" Option im Browser oder direkt gestartet werden. Kompatibel mit pwdhash.com.
5 |
6 | Diese App ist freie Software, die unter einer Open-Source-Lizenz bereitgestellt wird.
7 | Adresse der Webseite
8 | http://example.com
9 | Passwort
10 | Hash:
11 | Kopieren
12 | Das Passwort wurde in die Zwischenablage kopiert
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Ελαφρύ εργαλείο για να δημιουργήσει ιστοσελίδα συγκεκριμένη, κλοπή ανθεκτικών κωδικών πρόσβασης. Απλά χρησιμοποιήστε την \"Κοινή χρήση σελίδας\" στο πρόγραμμα περιήγησης Android ή ανοιχτό Hash κωδικό άμεσα. Συμβατό με pwdhash.com
5 |
6 | Αυτή η εφαρμογή είναι δωρεάν λογισμικό δημοσιευμένο με άδεια ανοιχτού κώδικα.
7 | Διεύθυνση ιστοσελίδας
8 | http://example.com
9 | Κωδικός
10 | Δίεση:
11 | Αντιγραφή
12 | Ο κωδικός αντιγράφεται στο πρόχειρο
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Herramienta ligera para generar contraseñas resistentes al robo, para sitios web específicos. Simplemente use la opción \"Compartir página\" en el navegador de Android, o directamente abra Password Hash. Compatible con pwdhash.com
5 |
6 | Esta aplicación es software libre publicado bajo una licencia de código abierto.
7 | Dirección del sitio
8 | http://example.com
9 | Contraseña
10 | Hash:
11 | Copiar
12 | Contraseña copiada al portapapeles
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mot de passe chiffré
4 | Utilitaire léger pour générer des mots de passe fiables contre les intrusions et spécifiques aux sites Web. Utiliser simplement l\'option « Partager page » dans le navigateur Android ou ouvrir Mot de passe chiffré directement. Compatible avec pwdhash.com.
5 |
6 | Cette appli est un logiciel gratuit publié sous licence « open source ».
7 | Adresse du site
8 | http://exemple.com
9 | Mot de passe
10 | Mot de passe chiffré :
11 | Copier
12 | Le mot de passe a été copié dans le presse-papiers
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-hr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Lagani alat za generiranje posebnih, otpornih na krađu lozinki. Samo iskoristite \"Share page\" opciju u Android Pretraživaču ili izravno otvorite Password Hash. Kompatibilno sa pwdhash.com
5 |
6 | Ova aplikacija je besplatan software izdan pod open-source licencom. (Preveo: Marijan Smetko, Novska, Hrvatska)
7 | Adresa stranice
8 | http://example.com
9 | Lozinka
10 | Hash:
11 | Kopiraj
12 | Lozinka je kopirana u međuspremnik
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Strumento leggero per generare password a prova di furto, specifiche per il web. Usa solo l\'opzione \"Condividi pagina\" nel tuo browser Android o apri direttamente Password Hash. Compatibile con pwdhash.com
5 |
6 | Questa app è software libero pubblicato sotto una licenza open source.
7 | Indirizzo del sito
8 | http://example.com
9 | Password
10 | Hash:
11 | Copia
12 | Password copiata negli appunti
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | ウェブサイトを指定して、盗難耐性パスワードを生成する、軽量のツールです。Android のブラウザから \"ページを共有\" オプションを使用するだけです。Password Hash を直接開くこともできます。 pwdhash.com と互換性があります。
5 |
6 | このアプリはオープンソースライセンスで公開されるフリーソフトウェアです。
7 | サイトアドレス
8 | http://example.com
9 | パスワード
10 | ハッシュ:
11 | コピー
12 | パスワードをクリップボードにコピーしました
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 비밀번호 생성기
4 | 훔쳐가기 힘든 암호를 웹 사이트 별로 생성하는 가벼운 도구입니다. 안드로이드 웹 브라우저에서 \"공유\" 옵션을 사용하거나, Password Hash를 바로 실행하시면 사용하실 수 있습니다. pwdhash.com과 호환됩니다.
5 |
6 | 이 앱은 오픈소스 라이선스 적용을 받는 무료 소프트웨어입니다.
7 | 사이트 주소
8 | http://example.com
9 | 비밀번호
10 | 생성된 비밀번호:
11 | 복사
12 | 비밀번호가 클립보드로 복사되었습니다
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nb-rNO/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Passordsjekksum
4 | Et lett verktøy for å generere nettsidespesifikke, tyverisikre passord. Trykk på \"Del side\" i Android-nettleseren eller åpne Passordsjekksum direkte. Kompatibelt med pwdhash.com.
5 |
6 | Dette programmet er publisert med en friprog-lisens.
7 | Sideadresse
8 | http://eksempel.no
9 | Passord
10 | Sjekksum:
11 | Kopier
12 | Passord kopiert til utklippstavle
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nl-rNL/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Wachtwoord hash
4 | Website adres
5 | http://www.example.nl
6 | Wachtwoord
7 | Hash:
8 | Kopiëren
9 | Wachtwoord gekopieerd naar het klembord
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hash hasła
4 | Lekkie narzędzie do generowania antywłamaniowy, konkretnych haseł do stron. Wystarczy skorzystać z opcji \"Poleć stronę\" w przeglądarce Android lub otworzyć Hash hasło bezpośrednio. Kompatybilne z pwdhash.com.
5 |
6 | Ta aplikacja jest darmowym oprogramowaniem na licencji open source.
7 | Adres strony
8 | http://przyklad.pl
9 | Hasło
10 | Hash:
11 | Kopiuj
12 | Hasło skopiowane do schowka
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Aplicativo para geração de senhas seguras para a internet. Use a opção \"Compartilhar página\" no navegador do Android ou abra Password Hash diretamente. Compatível com pwdhash.com.
5 |
6 | Este aplicativo é um software livre, lançado sob de código aberto.
7 | Endereço do site
8 | http://exemplo.com
9 | Senha
10 | Senha segura:
11 | Copiar
12 | Senha copiada para a área de transferência
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ro-rRO/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Un instrument lejer pentru generarea de parole rezistente la fraude, şi specifice site-urilor web. Trebuie doar să folosiţi opţiunea \"Partajare pagină\" din browserul Android, sau deschideţi direct Password Hash. Compatibil cu pwdhash.com.
5 |
6 | Această aplicaţie este un program gratuit publicat sub licenţă open source.
7 | Adresa sitului
8 | http://example.com
9 | Parola
10 | Hash:
11 | Copiere
12 | Parolă copiată în clipboard
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Удобный инструмент для создания паролей, привязанных к конкретным сайтам, из одного мастер-пароля. Просто используйте опцию \"Отправить страницу\" в браузере или вручную введите данные в Password Hash. Полностью совместим с pwdhash.com.
5 |
6 | Это приложение бесплатное и распространяется под открытой лицензией.
7 | Адрес сайта
8 | http://example.com
9 | Пароль
10 | Хеш:
11 | Копировать
12 | Пароль скопирован в буфер обмена
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Şifre Hash
4 | Özel web sitesi oluşturmak, hırsızlığa dayanıklı şifre yaratmak için hafif bir araçtır. Android tarayıcısında \'Paylaş\' butonunu kullanın veya Şifre Hash\'ı doğrudan açın. pwdhash.com ile uyumludur.
5 |
6 | Bu uygulama açık kaynak lisansı altında yayınlanan ücretsiz bir yazılımdır.
7 | Site adresi
8 | http://ornek.com
9 | Şifre
10 | Hash:
11 | Kopyala
12 | Şifre panoya kopyalandı
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Зручний інструмент для створення надійних паролів, прив\'язаних до конкретних сайтів. Просто використовуйте опцію \"Поділитись сторінкою\" в браузері або введіть дані прямо в Password Hash. Повністю сумісний з pwdhash.com.
5 | Цей додаток безкоштовний і поширюється під відкритою ліцензією.
6 | Адреса сайту
7 | http://example.com
8 | Пароль
9 | Хеш:
10 | Копіювати
11 | Пароль скопійований в буфер обміну
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/geometry.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 448dp
4 | 24dp
5 | 8dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-vi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mã hóa mật khẩu
4 | Là công cụ gọn nhẹ để nhúng vào các website, chống khả năng dòm trộm mật khẩu. Chỉ sử dụng tùy chọn \"Trang chia sẻ\" trong trình duyệt Android hoặc tác động đến việc hash hay còn gọi là băm mật khẩu trực tiếp. Tương thích với pwdhash.com.
5 |
6 | Phần mềm này được phân phối dưới dạng giấy phép mã nguồn mở.
7 | Địa chỉ trang web
8 | http://thídụ.com
9 | Mật khẩu
10 | Mã khóa:
11 | Sao chép
12 | Mật khẩu đã được lưu vào bộ nhớ ảo
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 密码加密
4 | 根据网址生成密码的小工具,可以通过浏览器的“分享页面”选项激活,或直接使用。与pwdhash.com生成的密码兼容。
5 | 本应用是自由软件,使用开源协议发布。
6 | 网址
7 | http://example.com
8 | 原始密码
9 | 加密密码
10 | 复制
11 | 密码已复制到剪贴板
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/geometry.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 448dp
4 | 12dp
5 | 4dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Password Hash
4 | Lightweight tool to generate website specific, theft-resistant passwords. Just use the "Share page" option in the Android browser or open Password Hash directly. Compatible with pwdhash.com.
5 |
6 | This app is free software published under an open source license.
7 | Site address
8 | http://example.com
9 | Password
10 | Hash:
11 | Copy
12 | Password copied to clipboard
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext {
4 | kotlin_version = '1.5.10'
5 | }
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:4.2.2'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | mavenCentral()
22 | maven {url "https://jitpack.io"}
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/design/feature-graphic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
121 |
--------------------------------------------------------------------------------
/design/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
169 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phw/Android-PwdHash/65d7cdf980b31eb05109699670cfefd74e475da3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 27 15:15:10 CEST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------