Password generator implemented

- Passwords also get's checked if it's compromised
This commit is contained in:
2020-07-13 19:17:43 +02:00
parent 2efdce87a8
commit 3ffd0e063f
26 changed files with 372 additions and 46 deletions

View File

@@ -41,6 +41,9 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
/* Password strengh library */
compile 'com.nulab-inc:zxcvbn:1.3.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"

View File

@@ -27,12 +27,16 @@ import com.google.zxing.BarcodeFormat
import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.integration.android.IntentResult
import com.journeyapps.barcodescanner.BarcodeEncoder
import com.nulabinc.zxcvbn.Zxcvbn
import dev.turingcomplete.kotlinonetimepassword.GoogleAuthenticator
import kotlinx.android.synthetic.main.activity_create.*
import kotlinx.android.synthetic.main.activity_generator.*
import kotlinx.android.synthetic.main.activity_generator.view.*
import kotlinx.android.synthetic.main.dialogpassphrase.view.*
import kotlinx.coroutines.*
import java.io.ByteArrayOutputStream
import java.lang.IllegalArgumentException
import java.lang.StringBuilder
import java.util.*
import kotlin.collections.ArrayList
@@ -168,6 +172,7 @@ class CreateActivity : AppCompatActivity() {
finish()
}
print_button.setOnClickListener {
fun continueAfterCheck() {
// Ask user for passhprase and hint
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.PassphraseDialog))
@@ -214,8 +219,23 @@ class CreateActivity : AppCompatActivity() {
})
show()
}
}
// First check if entered password is compromised
if (passwordKnown(password_input.text.toString())) {
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.ErrorDialog))
with(builder) {
setTitle("Password compromised!")
setMessage("Your password is weak and should be changed as it got found in a list of weak passwords.")
setPositiveButton("I'll change it", DialogInterface.OnClickListener { dialogInterface, i ->
})
setNegativeButton("I don't care", DialogInterface.OnClickListener { dialogInterface, i ->
continueAfterCheck()
})
show()
}
}
}
password_hide.setOnClickListener {
if (password_input.transformationMethod == HideReturnsTransformationMethod.getInstance()) {
@@ -227,6 +247,121 @@ class CreateActivity : AppCompatActivity() {
}
}
password_random.setOnClickListener {
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.PassphraseGenerator))
with (builder) {
val layout = layoutInflater.inflate(R.layout.activity_generator, null)
val zxcvbn = Zxcvbn()
var length: Int = 8
setTitle("Generate password")
setView(layout)
fun newPassword() {
var combined = ""
val upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
val lower_case = "abcdefghijklmnopqrstuvwxyz"
val speicals = "!\";#$%&'()*+,-./:;<=>?@[/]^_`"
val digits = "1234567890"
val emojis = arrayOf(0x1F600, 0x1F603, 0x1F601, 0x1F911, 0x1F910, 0x1F637, 0x1F47D, 0x1F480, 0x1F916)
val rand: Random = Random()
if (layout.AZ.isChecked) combined += upper_case
if (layout.az.isChecked) combined += lower_case
if (layout.zero_nine.isChecked) combined += digits
if (layout.emojis.isChecked) {
emojis.forEach {
combined += String(Character.toChars(it))
}
}
if (layout.special.isChecked) combined += speicals
val sb: StringBuilder = StringBuilder(length)
for (x in 1..length) {
sb.append(combined[rand.nextInt(combined.length)])
}
// Adapt text size
if (sb.length > 10) {
layout.random_string.textSize = 24.0f
} else if (sb.length > 16) {
layout.random_string.textSize = 18.0f
}
// Measure strengh
layout.progressBar.progress = zxcvbn.measure(sb.toString())
.score
if (layout.progressBar.progress == 1) {
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.RED)
} else if (layout.progressBar.progress == 2) {
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.YELLOW)
} else if (layout.progressBar.progress == 3) {
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.GREEN)
} else {
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.GREEN)
}
layout.random_string.setText(sb.toString())
}
// Initial set
layout.length_label.setText(length.toString())
newPassword()
// Add length
layout.add_button.setOnClickListener {
length++
layout.length_label.setText(length.toString())
newPassword()
}
layout.add_button.setOnLongClickListener {
length += 10
layout.length_label.setText(length.toString())
newPassword()
true
}
// Subtract length
layout.subtract_button.setOnClickListener {
length--
layout.length_label.setText(length.toString())
newPassword()
}
layout.subtract_button.setOnLongClickListener {
length -= 10
layout.length_label.setText(length.toString())
newPassword()
true
}
// Refresh
layout.refresh_button.setOnClickListener {
newPassword()
}
// Copy password
layout.copy_button.setOnClickListener {
// Copy code if already scanend
val clip: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clip.setPrimaryClip(ClipData.newPlainText("Random password", layout.random_string.text.toString()))
Toast.makeText(applicationContext, "Copied!", Toast.LENGTH_SHORT).show()
}
setPositiveButton("Use this",
DialogInterface.OnClickListener { dialog, id ->
password_input.setText(layout.random_string.text)
})
setNegativeButton("Go back",
DialogInterface.OnClickListener { dialog, id ->
dialog.dismiss()
})
show()
}
}
fa_input.isFocusable = false

View File

@@ -2,10 +2,27 @@ package com.github.mondei1.offpass
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_generator.*
class GeneratorActivity : AppCompatActivity() {
var length: Int = 12
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_generator)
length_label.setText(length.toString())
Log.i("Generator", "Length: $length")
add_button.setOnClickListener {
Log.i("Generator", "Length: $length")
length++
length_label.setText(length.toString())
}
subtract_button.setOnClickListener {
Log.i("Generator", "Length: $length")
length--
length_label.setText(length.toString())
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,9 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".GeneratorActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="350dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="256dp"
android:layout_height="10dp"
android:layout_marginStart="80dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="80dp"
android:progress="2"
android:min="0"
android:max="4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/random_string"
android:layout_width="201dp"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:layout_marginEnd="80dp"
android:layout_marginBottom="10dp"
android:gravity="center_vertical"
android:text="D%g$MA0H8d"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textSize="30sp"
app:layout_constraintBottom_toTopOf="@+id/progressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/refresh_button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:background="#00FFFFFF"
app:layout_constraintBottom_toTopOf="@+id/progressBar"
app:layout_constraintEnd_toStartOf="@+id/random_string"
app:srcCompat="@drawable/ic_refresh" />
<ImageButton
android:id="@+id/copy_button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:background="#00FFFFFF"
app:layout_constraintBottom_toTopOf="@+id/progressBar"
app:layout_constraintStart_toEndOf="@+id/random_string"
app:srcCompat="@drawable/ic_content_copy" />
<LinearLayout
android:id="@+id/password_length_container"
android:layout_width="142dp"
android:layout_height="45dp"
android:layout_marginStart="1dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="1dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar">
<ImageButton
android:id="@+id/subtract_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/ic_remove" />
<TextView
android:id="@+id/length_label"
android:layout_width="45dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal|center_vertical"
android:text="0"
android:textColor="@color/colorPrimaryDark"
android:textSize="24sp" />
<ImageButton
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/ic_add" />
</LinearLayout>
<CheckBox
android:id="@+id/AZ"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:checked="true"
android:text="A-Z"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/password_length_container" />
<CheckBox
android:id="@+id/az"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:checked="true"
android:text="a-z"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/AZ" />
<CheckBox
android:id="@+id/zero_nine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:checked="true"
android:text="0-9"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/az" />
<CheckBox
android:id="@+id/special"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:checked="true"
android:text="!&quot;#$%'()*+"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/zero_nine" />
<CheckBox
android:id="@+id/emojis"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:text="😃👽😺👋"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/special" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@@ -22,7 +22,9 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal">
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/back"

View File

@@ -19,4 +19,11 @@
<item name="android:textStyle">bold</item>
<item name="android:background">@android:color/holo_red_light</item>
</style>
<style name="PassphraseGenerator" parent="@android:style/Theme.Material.Dialog">
<item name="android:paddingTop">0dp</item>
<item name="android:layout_marginTop">0dp</item>
<item name="android:textColor">@color/colorPrimaryDark</item>
<item name="background">@color/colorPrimary</item>
<item name="android:textStyle">bold</item>
</style>
</resources>