From 8865e9a3947af4c34d956f906ff995261b1ee81b Mon Sep 17 00:00:00 2001 From: Mondei1 Date: Thu, 9 Jul 2020 16:18:49 +0200 Subject: [PATCH] QR-Codes can now be displayed after scanning. - 2FA also supported --- app/src/main/AndroidManifest.xml | 6 +- .../drawable => assets}/dummy_qr_code.png | Bin app/src/main/assets/print_background.png | Bin 0 -> 31866 bytes .../main/{res/font => assets}/robotobold.ttf | Bin .../{res/font => assets}/robotoregular.ttf | Bin .../main/{res/font => assets}/robotothin.ttf | Bin .../github/mondei1/offpass/CreateActivity.kt | 91 +++++-- .../mondei1/offpass/CryptoOperations.kt | 2 +- .../github/mondei1/offpass/MainActivity.kt | 8 +- .../mondei1/offpass/PassphraseActivity.kt | 34 +++ .../com/github/mondei1/offpass/QRSchema.kt | 26 +- .../github/mondei1/offpass/ViewActivity.kt | 77 ++++++ app/src/main/res/layout/activity_create.xml | 6 +- .../main/res/layout/activity_passphrase.xml | 65 +++++ app/src/main/res/layout/activity_view.xml | 227 ++++++++++++++++++ app/src/main/res/layout/create_bar.xml | 2 +- app/src/main/res/{ => raw}/print.html | 50 ++-- 17 files changed, 532 insertions(+), 62 deletions(-) rename app/src/main/{res/drawable => assets}/dummy_qr_code.png (100%) create mode 100644 app/src/main/assets/print_background.png rename app/src/main/{res/font => assets}/robotobold.ttf (100%) rename app/src/main/{res/font => assets}/robotoregular.ttf (100%) rename app/src/main/{res/font => assets}/robotothin.ttf (100%) create mode 100644 app/src/main/java/com/github/mondei1/offpass/PassphraseActivity.kt create mode 100644 app/src/main/java/com/github/mondei1/offpass/ViewActivity.kt create mode 100644 app/src/main/res/layout/activity_passphrase.xml create mode 100644 app/src/main/res/layout/activity_view.xml rename app/src/main/res/{ => raw}/print.html (59%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 858d190..54bf586 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,11 +12,13 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + + + android:windowSoftInputMode="adjustPan" /> diff --git a/app/src/main/res/drawable/dummy_qr_code.png b/app/src/main/assets/dummy_qr_code.png similarity index 100% rename from app/src/main/res/drawable/dummy_qr_code.png rename to app/src/main/assets/dummy_qr_code.png diff --git a/app/src/main/assets/print_background.png b/app/src/main/assets/print_background.png new file mode 100644 index 0000000000000000000000000000000000000000..53625c261ed9a372270dbab0053dd98ae0b63ae6 GIT binary patch literal 31866 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 Q1WJ_OneWZ~miFWS0U#X9xBvhE literal 0 HcmV?d00001 diff --git a/app/src/main/res/font/robotobold.ttf b/app/src/main/assets/robotobold.ttf similarity index 100% rename from app/src/main/res/font/robotobold.ttf rename to app/src/main/assets/robotobold.ttf diff --git a/app/src/main/res/font/robotoregular.ttf b/app/src/main/assets/robotoregular.ttf similarity index 100% rename from app/src/main/res/font/robotoregular.ttf rename to app/src/main/assets/robotoregular.ttf diff --git a/app/src/main/res/font/robotothin.ttf b/app/src/main/assets/robotothin.ttf similarity index 100% rename from app/src/main/res/font/robotothin.ttf rename to app/src/main/assets/robotothin.ttf diff --git a/app/src/main/java/com/github/mondei1/offpass/CreateActivity.kt b/app/src/main/java/com/github/mondei1/offpass/CreateActivity.kt index bbd4c8d..7064c9f 100644 --- a/app/src/main/java/com/github/mondei1/offpass/CreateActivity.kt +++ b/app/src/main/java/com/github/mondei1/offpass/CreateActivity.kt @@ -1,48 +1,97 @@ package com.github.mondei1.offpass -import android.animation.ObjectAnimator import android.annotation.SuppressLint import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.res.ColorStateList +import android.graphics.Bitmap import android.graphics.Color -import android.graphics.ColorFilter import android.net.Uri import android.os.Bundle -import android.text.Editable +import android.print.PrintAttributes +import android.print.PrintJob +import android.print.PrintManager +import android.util.Base64 import android.util.Log import android.view.View -import android.view.animation.LinearInterpolator +import android.webkit.WebResourceRequest +import android.webkit.WebView +import android.webkit.WebViewClient import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.isVisible +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 dev.turingcomplete.kotlinonetimepassword.GoogleAuthenticator import kotlinx.android.synthetic.main.activity_create.* import kotlinx.coroutines.* -import java.text.DateFormat -import java.text.SimpleDateFormat +import java.io.ByteArrayOutputStream import java.util.* class CreateActivity : AppCompatActivity() { - private var fragment_title: TextInput? = null - private var fragment_username: TextInput? = null private var schema: QRSchema? = null + private var qrCodeBitmap: Bitmap? = null private var fa_coroutine: Job? = null + private var mWebView: WebView? = null + private var printJob: PrintJob? = null + + fun doPrint() { + val webView = WebView(this) + webView.webViewClient = object : WebViewClient() { + override fun shouldOverrideUrlLoading(view: WebView, requesst: WebResourceRequest) = false + + override fun onPageFinished(view: WebView?, url: String?) { + Log.i("Create Activity", "Template page finished loading") + createWebPrintJob(webView) + mWebView = null + } + } + + var htmlDocument = String(this.resources.openRawResource( + this.resources.getIdentifier("print", "raw", this.packageName) + ).readBytes()).replace("\n", "") + + // Prepare html document + var byteArrayOutputStream = ByteArrayOutputStream() + this.qrCodeBitmap?.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) + htmlDocument = htmlDocument.replace("\$DATE", Date().time.toString()) + .replace("\$HINT", "Not configurable yet!") + .replace("\$QRCODE", Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.NO_WRAP)) + + Log.i("Create Activity", htmlDocument) + webView.loadDataWithBaseURL("file:///android_asset/", htmlDocument, "text/HTML", "UTF-8", null) + + mWebView = webView + } + + fun createWebPrintJob(webView: WebView) { + (this.getSystemService(Context.PRINT_SERVICE) as? PrintManager)?.let { printManager -> + val jobName = "Offpass Document" + val printAdapter = webView.createPrintDocumentAdapter(jobName) + + printManager.print( + jobName, + printAdapter, + PrintAttributes.Builder().build() + ).also { printJob -> + this.printJob = printJob + } + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - //this.schema = QRSchema(this) - //this.schema!!.decrypted_raw = "%JtuB4O9M42%Gitea|Nicolas|542superGoOD_pW&|klier.nicolas@protonmail.com|\$ul|(\$vb)\$O4|()What's your favorite series%Rick and morty|(2fa)otpauth://totp/OffPass%20Test?secret=d34gfkki5dkd5knifysrpgndd5xb2c7eddwki7ya4pvoisfa5c3ko5pv&issuer=Nicolas%20Klier" - //this.schema!!.parse(this) + this.schema = QRSchema(this) + this.schema!!.decrypted_raw = "%JtuB4O9M42%Gitea|Nicolas|542superGoOD_pW&|klier.nicolas@protonmail.com|\$ul|(\$vb)\$O4|()What's your favorite series%Rick and morty|(2fa)otpauth://totp/OffPass%20Test?secret=d34gfkki5dkd5knifysrpgndd5xb2c7eddwki7ya4pvoisfa5c3ko5pv&issuer=Nicolas%20Klier" + this.schema!!.parse(this) - //this.schema!!.build(arrayOf("website_url", "2fa", "What's your favorite series"), "123") - //this.schema!!.decrypt(this.schema!!.raw, "123") + this.schema!!.build(arrayOf("website_url", "2fa", "What's your favorite series"), "123") + this.schema!!.decrypt(this.schema!!.raw, "123") setSupportActionBar(findViewById(R.id.toolbar)) @@ -51,6 +100,20 @@ class CreateActivity : AppCompatActivity() { Log.i("CREATE", "Back got clicked!") finish() } + print_button.setOnClickListener { + // Set up printing + this.schema = QRSchema(this) + this.schema!!.title = title_input.text.toString() + this.schema!!.username = username_input.text.toString() + this.schema!!.password = password_input.text.toString() + this.schema!!.email = email_input.text.toString() + this.schema!!.website_url = url_input.text.toString() + this.schema!!.build(arrayOf(), "123") + + val barcodeEncoder: BarcodeEncoder = BarcodeEncoder() + this.qrCodeBitmap = barcodeEncoder.encodeBitmap(this.schema!!.raw, BarcodeFormat.QR_CODE, 400, 400) + doPrint() + } fa_input.isFocusable = false diff --git a/app/src/main/java/com/github/mondei1/offpass/CryptoOperations.kt b/app/src/main/java/com/github/mondei1/offpass/CryptoOperations.kt index 628e85f..d22bad6 100644 --- a/app/src/main/java/com/github/mondei1/offpass/CryptoOperations.kt +++ b/app/src/main/java/com/github/mondei1/offpass/CryptoOperations.kt @@ -117,7 +117,7 @@ class CryptoOperations { // Performing actual crypto operation cipher.init(Cipher.DECRYPT_MODE, keySpec, IvParameterSpec(iv)) - val ciphered = cipher.doFinal(encrypted_raw) + val ciphered = cipher.doFinal(encrypted_raw) // TODO: Catch error if decryption goes wrong // Concat everything into one byte array val byteBuffer: ByteBuffer = ByteBuffer.allocate(ciphered.size) diff --git a/app/src/main/java/com/github/mondei1/offpass/MainActivity.kt b/app/src/main/java/com/github/mondei1/offpass/MainActivity.kt index 0b615ef..ddb733c 100644 --- a/app/src/main/java/com/github/mondei1/offpass/MainActivity.kt +++ b/app/src/main/java/com/github/mondei1/offpass/MainActivity.kt @@ -2,7 +2,6 @@ package com.github.mondei1.offpass import android.content.Intent import android.os.Bundle -import android.os.HandlerThread import android.util.Log import android.widget.Toast import androidx.appcompat.app.AppCompatActivity @@ -61,8 +60,11 @@ class MainActivity : AppCompatActivity() { if (result.contents == null) { Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show() } else { - Log.i("SCANNER", "Scanned: " + result.contents) - Toast.makeText(this, "Scanned: " + result.contents, Toast.LENGTH_LONG).show() + // TODO: Check if scanned QR-Code is an OffPass one. + val intent: Intent = Intent(this, PassphraseActivity::class.java) + intent.putExtra("raw", result.contents) + startActivity(intent) + //Toast.makeText(this, "Scanned: " + result.contents, Toast.LENGTH_LONG).show() } } diff --git a/app/src/main/java/com/github/mondei1/offpass/PassphraseActivity.kt b/app/src/main/java/com/github/mondei1/offpass/PassphraseActivity.kt new file mode 100644 index 0000000..4c8e093 --- /dev/null +++ b/app/src/main/java/com/github/mondei1/offpass/PassphraseActivity.kt @@ -0,0 +1,34 @@ +package com.github.mondei1.offpass + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.text.Editable +import kotlinx.android.synthetic.main.activity_passphrase.* +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.runBlocking + +class PassphraseActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_passphrase) + + val raw: String = intent.getStringExtra("raw")!! + val qrSchema: QRSchema = QRSchema(this) + + back.setOnClickListener { + finish() + } + + decrypt_button.setOnClickListener { + decrypt_button.text = "Decrypting ..." + runBlocking { + qrSchema.decrypt(raw, passphrase_input.text.toString()) + } + + val intent: Intent = Intent(this, ViewActivity::class.java) + intent.putExtra("decrypted_raw",qrSchema.decrypted_raw) + startActivity(intent) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/mondei1/offpass/QRSchema.kt b/app/src/main/java/com/github/mondei1/offpass/QRSchema.kt index 5391a06..3ed8ef4 100644 --- a/app/src/main/java/com/github/mondei1/offpass/QRSchema.kt +++ b/app/src/main/java/com/github/mondei1/offpass/QRSchema.kt @@ -18,7 +18,7 @@ class QRSchema { var decrypted_raw: String = "" // Parsed content - lateinit var session_key: String + var session_key: String = "" lateinit var title: String lateinit var username: String lateinit var password: String @@ -100,23 +100,23 @@ class QRSchema { var key = fields[i].substring(1, closingBracket) var value = fields[i].substring(closingBracket+1, fields[i].length) - // Check if key and or value are compressed - if (key.startsWith("$")) { - runBlocking { - key = resolve(key, context) - } - } - if (value.startsWith("$")) { - runBlocking { - value = resolve(value, context) - } - } - // We got a security question/awnser if (key == "") { val qa = value.split("%") question_awnser.put(qa[0], qa[1]); } else { + // Check if key and or value are compressed + if (key.startsWith("$")) { + runBlocking { + key = resolve(key, context) + } + } + if (value.startsWith("$")) { + runBlocking { + value = resolve(value, context) + } + } + custom.put(key, value) } } else { diff --git a/app/src/main/java/com/github/mondei1/offpass/ViewActivity.kt b/app/src/main/java/com/github/mondei1/offpass/ViewActivity.kt new file mode 100644 index 0000000..ec3c1f6 --- /dev/null +++ b/app/src/main/java/com/github/mondei1/offpass/ViewActivity.kt @@ -0,0 +1,77 @@ +package com.github.mondei1.offpass + +import android.R.attr.key +import android.annotation.SuppressLint +import android.content.Intent +import android.content.res.ColorStateList +import android.graphics.Color +import android.net.Uri +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import dev.turingcomplete.kotlinonetimepassword.GoogleAuthenticator +import kotlinx.android.synthetic.main.activity_view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + + +class ViewActivity : AppCompatActivity() { + @SuppressLint("SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_view) + + val qrSchema: QRSchema = QRSchema(this) + + back.setOnClickListener { + val i = Intent(this, MainActivity::class.java) + i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + startActivity(i) + } + + qrSchema.decrypted_raw = intent.getStringExtra("decrypted_raw")!! + qrSchema.parse(this) + + title_label.text = qrSchema.title + username_input.setText(qrSchema.username, TextView.BufferType.EDITABLE) + password_input.setText(qrSchema.password, TextView.BufferType.EDITABLE) + email_input.setText(qrSchema.email, TextView.BufferType.EDITABLE) + url_input.setText(qrSchema.website_url, TextView.BufferType.EDITABLE) + + if (qrSchema.custom.containsKey("2fa")) { + val fa_uri = Uri.parse(qrSchema.custom.get("2fa")) + val fa_generator = GoogleAuthenticator(base32secret = fa_uri.getQueryParameter("secret").toString()) + fa_label.text = "${fa_uri.path?.replace("/", "")} (${fa_uri.getQueryParameter("issuer")})" + fa_progress.visibility = View.VISIBLE + + GlobalScope.launch(Dispatchers.Main) { + while (true) { + fa_input.setText(fa_generator.generate()) + + var seconds_remaining = CryptoOperations().getRemainingTOTPTime() + Log.i("2FA Generator", "Remaining: $seconds_remaining") + + if (seconds_remaining == 0) seconds_remaining = 30 + + // Change color + if (seconds_remaining >= 15) { + fa_progress.progressTintList = ColorStateList.valueOf(Color.GREEN) + } else if (seconds_remaining < 15 && seconds_remaining >= 8) { + fa_progress.progressTintList = ColorStateList.valueOf(Color.YELLOW) + } else { + fa_progress.progressTintList = ColorStateList.valueOf(Color.RED) + } + + fa_progress.progress = seconds_remaining + delay(1000) + } + } + } else { + fa_layout.visibility = View.GONE + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_create.xml b/app/src/main/res/layout/activity_create.xml index 1183075..be6d949 100644 --- a/app/src/main/res/layout/activity_create.xml +++ b/app/src/main/res/layout/activity_create.xml @@ -14,19 +14,19 @@ android:layout_height="wrap_content" android:background="@color/colorPrimaryDark" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:title="Create"> + app:layout_constraintTop_toTopOf="parent"> + + + + +