Basic schema parser implemented
@@ -8,6 +8,7 @@ import kotlinx.android.synthetic.main.activity_create.*
|
|||||||
class CreateActivity : AppCompatActivity() {
|
class CreateActivity : AppCompatActivity() {
|
||||||
private var fragment_title: TextInput? = null
|
private var fragment_title: TextInput? = null
|
||||||
private var fragment_username: TextInput? = null
|
private var fragment_username: TextInput? = null
|
||||||
|
private var schema: QRSchema? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -19,6 +20,10 @@ class CreateActivity : AppCompatActivity() {
|
|||||||
.replace(R.id.username, fragment_username!!)
|
.replace(R.id.username, fragment_username!!)
|
||||||
.commit()
|
.commit()
|
||||||
|
|
||||||
|
this.schema = QRSchema()
|
||||||
|
this.schema!!.decrypted_raw = "%JtuB4O9M42%Gitea|Nicolas|542superGoOD_pW&|klier.nicolas@protonmail.com|https://nicolasklier.de:3000|()What's your favorite series%Rick and morty|(2fa)otpauth://totp/OffPass%20Test?secret=d34gfkki5dkd5knifysrpgndd5xb2c7eddwki7ya4pvoisfa5c3ko5pv&issuer=Nicolas%20Klier"
|
||||||
|
this.schema!!.parse()
|
||||||
|
|
||||||
setSupportActionBar(findViewById(R.id.toolbar))
|
setSupportActionBar(findViewById(R.id.toolbar))
|
||||||
|
|
||||||
setContentView(R.layout.activity_create)
|
setContentView(R.layout.activity_create)
|
||||||
|
|||||||
84
app/src/main/java/com/github/mondei1/offpass/QRSchema.kt
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package com.github.mondei1.offpass
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import java.lang.Error
|
||||||
|
import java.util.regex.Matcher
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class QRSchema {
|
||||||
|
|
||||||
|
var raw: String = ""
|
||||||
|
var decrypted_raw: String = ""
|
||||||
|
|
||||||
|
// Parsed content
|
||||||
|
lateinit var session_key: String
|
||||||
|
lateinit var title: String
|
||||||
|
lateinit var username: String
|
||||||
|
lateinit var password: String
|
||||||
|
lateinit var email: String
|
||||||
|
lateinit var website_url: String
|
||||||
|
var custom: HashMap<String, String> = HashMap() // All defined custom/optional fields
|
||||||
|
var question_awnser: HashMap<String, String> = HashMap() // Used for security questions
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will take the already set raw content and tries to parse it.
|
||||||
|
*
|
||||||
|
* @return It will return `true` if the operation was successful and `false` if otherwise.
|
||||||
|
*/
|
||||||
|
fun parse(): Boolean {
|
||||||
|
if (decrypted_raw == "") {
|
||||||
|
throw Error("Tried to parse QR-Code schema but raw content must be first decrypted! " +
|
||||||
|
"Set raw content first and then use decrypt()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// First will be to split the string into it's parts
|
||||||
|
var fields: MutableList<String> = this.decrypted_raw.split("|").toMutableList()
|
||||||
|
|
||||||
|
for (i in 0 until fields.size) {
|
||||||
|
// First four items have to exist and are title, username, password, URL in this order.
|
||||||
|
if (i == 0) {
|
||||||
|
// Check if there is a session key
|
||||||
|
if (fields[0].startsWith("%")) {
|
||||||
|
fields[0] = fields[0].replace("%", "")
|
||||||
|
session_key = fields[0].substring(0, 9) // Get first 10 chars, which are the
|
||||||
|
// session key
|
||||||
|
this.title = fields[0].substring(10, fields[0].length)
|
||||||
|
} else {
|
||||||
|
this.title = fields[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.username = fields[1]
|
||||||
|
this.password = fields[2]
|
||||||
|
this.email = fields[3]
|
||||||
|
this.website_url = fields[4]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here are optional/custom fields
|
||||||
|
if (i > 4) {
|
||||||
|
if (fields[i].startsWith("(")) {
|
||||||
|
var closingBracket = fields[i].indexOf(")")
|
||||||
|
var key = fields[i].substring(1, closingBracket)
|
||||||
|
var value = fields[i].substring(closingBracket+1, fields[i].length)
|
||||||
|
|
||||||
|
// We got a security question/awnser
|
||||||
|
if (key == "") {
|
||||||
|
var qa = value.split("%")
|
||||||
|
question_awnser.put(qa[0], qa[1]);
|
||||||
|
} else {
|
||||||
|
custom.put(key, value)
|
||||||
|
}
|
||||||
|
Log.i("QR-Code schema", custom.toString())
|
||||||
|
} else {
|
||||||
|
throw Error("Custom/optional field should start with an open bracket: "
|
||||||
|
+ fields[i].toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i("QR-Code schema", "Found: $session_key, $title, $username, $password, $email, $website_url. ${custom.toString()} and ${question_awnser.toString()}")
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
app/src/main/res/drawable-hdpi/baseline_shuffle_black_18.png
Normal file
|
After Width: | Height: | Size: 234 B |
BIN
app/src/main/res/drawable-hdpi/baseline_shuffle_black_24.png
Normal file
|
After Width: | Height: | Size: 248 B |
BIN
app/src/main/res/drawable-hdpi/baseline_shuffle_black_36.png
Normal file
|
After Width: | Height: | Size: 314 B |
BIN
app/src/main/res/drawable-hdpi/baseline_shuffle_black_48.png
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
app/src/main/res/drawable-hdpi/baseline_visibility_black_18.png
Normal file
|
After Width: | Height: | Size: 387 B |
BIN
app/src/main/res/drawable-hdpi/baseline_visibility_black_24.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/drawable-hdpi/baseline_visibility_black_36.png
Normal file
|
After Width: | Height: | Size: 662 B |
BIN
app/src/main/res/drawable-hdpi/baseline_visibility_black_48.png
Normal file
|
After Width: | Height: | Size: 819 B |
BIN
app/src/main/res/drawable-mdpi/baseline_shuffle_black_18.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
app/src/main/res/drawable-mdpi/baseline_shuffle_black_24.png
Normal file
|
After Width: | Height: | Size: 197 B |
BIN
app/src/main/res/drawable-mdpi/baseline_shuffle_black_36.png
Normal file
|
After Width: | Height: | Size: 248 B |
BIN
app/src/main/res/drawable-mdpi/baseline_shuffle_black_48.png
Normal file
|
After Width: | Height: | Size: 290 B |
BIN
app/src/main/res/drawable-mdpi/baseline_visibility_black_18.png
Normal file
|
After Width: | Height: | Size: 255 B |
BIN
app/src/main/res/drawable-mdpi/baseline_visibility_black_24.png
Normal file
|
After Width: | Height: | Size: 340 B |
BIN
app/src/main/res/drawable-mdpi/baseline_visibility_black_36.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/drawable-mdpi/baseline_visibility_black_48.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_shuffle_black_18.png
Normal file
|
After Width: | Height: | Size: 248 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_shuffle_black_24.png
Normal file
|
After Width: | Height: | Size: 290 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_shuffle_black_36.png
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_shuffle_black_48.png
Normal file
|
After Width: | Height: | Size: 469 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_visibility_black_18.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_visibility_black_24.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_visibility_black_36.png
Normal file
|
After Width: | Height: | Size: 819 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_visibility_black_48.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/baseline_shuffle_black_18.png
Normal file
|
After Width: | Height: | Size: 314 B |
BIN
app/src/main/res/drawable-xxhdpi/baseline_shuffle_black_24.png
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
app/src/main/res/drawable-xxhdpi/baseline_shuffle_black_36.png
Normal file
|
After Width: | Height: | Size: 507 B |
BIN
app/src/main/res/drawable-xxhdpi/baseline_shuffle_black_48.png
Normal file
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 662 B |
|
After Width: | Height: | Size: 819 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_shuffle_black_18.png
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_shuffle_black_24.png
Normal file
|
After Width: | Height: | Size: 469 B |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_shuffle_black_36.png
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_shuffle_black_48.png
Normal file
|
After Width: | Height: | Size: 776 B |
|
After Width: | Height: | Size: 819 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
10
app/src/main/res/drawable/baseline_shuffle_24.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M10.59,9.17L5.41,4 4,5.41l5.17,5.17 1.42,-1.41zM14.5,4l2.04,2.04L4,18.59 5.41,20 17.96,7.46 20,9.5L20,4h-5.5zM14.83,13.41l-1.41,1.41 3.13,3.13L14.5,20L20,20v-5.5l-2.04,2.04 -3.13,-3.13z"/>
|
||||||
|
</vector>
|
||||||
10
app/src/main/res/drawable/baseline_visibility_24.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/colorPrimaryDark">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
|
||||||
|
</vector>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@@ -28,4 +29,13 @@
|
|||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
android:hint="@string/text_input_title_undefined" />
|
android:hint="@string/text_input_title_undefined" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/imageButton2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="350dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:src="@drawable/baseline_visibility_black_48" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||