Password generator implemented
- Passwords also get's checked if it's compromised
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 1011 B |
BIN
app/src/main/res/drawable-hdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 526 B |
BIN
app/src/main/res/drawable-mdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 395 B |
BIN
app/src/main/res/drawable-mdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 914 B |
BIN
app/src/main/res/drawable-mdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 233 B |
BIN
app/src/main/res/drawable-xhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
@@ -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
|
||||
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="!"#$%'()*+"
|
||||
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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||