This is a follow-up question for Android APP User class implementation. I am attempting to create a password strength assessment class which is named PasswordStrengthAssessment
in Java. Instead of adding "111111", "123123" or the other weak passwords one by one in program, the 10k-most-common.txt on Github is used as the list of common passwords. After constructing PasswordStrengthAssessment
class, this 10k-most-common.txt
is going to be downloaded and this design may make the matching operation for weak password detection be better. However, the network resource availability and the download time are need to be considered.
The experimental implementation
Project name: PasswordStrengthAssessment
PasswordStrengthAssessment
class implementation:package com.example.passwordstrengthassessment; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class PasswordStrengthAssessment extends AppCompatActivity { private List<String> commonPasswords = new ArrayList<String>(); private final int minimumLengthRequired = 8; public enum Level { Weak, Medium, Strong // TODO: Implement the determination of strong level password } // Empty constructor public PasswordStrengthAssessment() { try { createCommonPasswordsList(); } catch (InterruptedException ex) { ex.printStackTrace(); } } // Reference: // 10k-most-common.txt: https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt private void createCommonPasswordsList() throws InterruptedException { Runnable downloadCommonPasswordsListRunnable = () -> { final String mostCommonPasswordList = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/10k-most-common.txt"; try { // Create a URL for the desired page URL url = new URL(mostCommonPasswordList); // Read all the text returned by the server BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String str; while ((str = in.readLine()) != null) { // Reference: https://stackoverflow.com/a/15949198/6667035 synchronized(this.commonPasswords) { this.commonPasswords.add(str); } Log.d("downloadCommonPasswordsListRunnable", str); } in.close(); } catch (MalformedURLException e) { Log.d("createCommonPasswordsList", e.getMessage()); e.printStackTrace(); } catch (IOException e) { Log.d("createCommonPasswordsList", e.getMessage()); e.printStackTrace(); } }; Thread thread = new Thread(downloadCommonPasswordsListRunnable); thread.start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } if (this.commonPasswords.size() == 0) // Common Passwords List download fail { createCommonPasswordsListLocal(); } return; } private void createCommonPasswordsListLocal() { this.commonPasswords.add(getResources().getString(R.string.common_password1)); this.commonPasswords.add(getResources().getString(R.string.common_password2)); this.commonPasswords.add(getResources().getString(R.string.common_password3)); this.commonPasswords.add(getResources().getString(R.string.common_password4)); this.commonPasswords.add(getResources().getString(R.string.common_password5)); this.commonPasswords.add(getResources().getString(R.string.common_password6)); this.commonPasswords.add(getResources().getString(R.string.common_password7)); this.commonPasswords.add(getResources().getString(R.string.common_password8)); this.commonPasswords.add(getResources().getString(R.string.common_password9)); this.commonPasswords.add(getResources().getString(R.string.common_password10)); this.commonPasswords.add(getResources().getString(R.string.common_password11)); this.commonPasswords.add(getResources().getString(R.string.common_password12)); return; } private boolean lengthCheck(final String input) { if (input.length() > minimumLengthRequired) { return true; } return false; } public boolean isPasswordWeak(final String passwordInput) { return determinePasswordStrength(passwordInput).equals(Level.Weak); } private Level determinePasswordStrength(final String passwordInput) { if (lengthCheck(passwordInput) == false) { return Level.Weak; } if (this.commonPasswords.contains(passwordInput)) { return Level.Weak; } return Level.Medium; } }
strings.xml
<resources> <string name="app_name">PasswordStrengthAssessment</string> <string name="common_password1">111111</string> <string name="common_password2">123123</string> <string name="common_password3">12345</string> <string name="common_password4">123456</string> <string name="common_password5">12345678</string> <string name="common_password6">123456789</string> <string name="common_password7">1234567890</string> <string name="common_password8">picture1</string> <string name="common_password9">password</string> <string name="common_password10">password123</string> <string name="common_password11">Password</string> <string name="common_password12">Password123</string> </resources>
User permission setting
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.passwordstrengthassessment"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.PasswordStrengthAssessment"> <activity android:name=".MainActivity" android:exported="true" android:usesCleartextTraffic="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> </manifest>
build.gradle
plugins { id 'com.android.application' } android { compileSdk 30 defaultConfig { applicationId "com.example.passwordstrengthassessment" minSdk 26 targetSdk 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } } dependencies { implementation 'androidx.appcompat:appcompat:1.3.0' implementation fileTree(include: ['*.jar'], dir: 'libs') // https://mvnrepository.com/artifact/commons-net/commons-net implementation group: 'commons-net', name: 'commons-net', version: '20030805.205232' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
Full Testing Code
MainActivity.java
implementation:package com.example.passwordstrengthassessment; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import java.util.concurrent.TimeUnit; public class MainActivity extends AppCompatActivity { private static final int READ_EXTERNAL_STORAGE_CODE = 1; private static final int WRITE_EXTERNAL_STORAGE_CODE = 2; private static final int ACCESS_NETWORK_STATE_CODE = 3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE_CODE); checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE_CODE); checkPermission(Manifest.permission.ACCESS_NETWORK_STATE, ACCESS_NETWORK_STATE_CODE); PasswordStrengthAssessment passwordStrengthAssessment = new PasswordStrengthAssessment(); showToast("Is dogggg a weak password:" + String.valueOf(passwordStrengthAssessment.isPasswordWeak("dogggg")), Toast.LENGTH_SHORT); } // Function to check and request permission. public void checkPermission(String permission, int requestCode) { if (ContextCompat.checkSelfPermission(MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) { // Requesting the permission ActivityCompat.requestPermissions(MainActivity.this, new String[] { permission }, requestCode); } else { Toast.makeText(MainActivity.this, "Permission already granted", Toast.LENGTH_SHORT).show(); } } void showToast(String Text, int Duration) { Context context = getApplicationContext(); CharSequence text = Text; int duration = Duration; Toast toast = Toast.makeText(context, text, duration); toast.show(); } }
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
What changes has been made in the code since last question?
Instead of adding "111111", "123123" or the other weak passwords one by one in program, the 10k-most-common.txt on Github is used as the list of common passwords here.
Why a new review is being asked for?
If there is any possible improvement, please let me know.