aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenFragment.kt
blob: 923b53a45b617f80a8ee66d6c73900abe41cfa55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
 * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
 * SPDX-License-Identifier: GPL-3.0-only
 */
package com.zeapo.pwdstore.sshkeygen

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jcraft.jsch.JSch
import com.jcraft.jsch.KeyPair
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.databinding.FragmentSshKeygenBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream

class SshKeyGenFragment : Fragment() {

    private var keyLength = 4096
    private var _binding: FragmentSshKeygenBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentSshKeygenBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        with(binding) {
            generate.setOnClickListener {
                lifecycleScope.launch { generate(passphrase.text.toString(), comment.text.toString()) }
            }
            keyLengthGroup.check(R.id.key_length_4096)
            keyLengthGroup.addOnButtonCheckedListener { _, checkedId, isChecked ->
                if (isChecked) {
                    when (checkedId) {
                        R.id.key_length_2048 -> keyLength = 2048
                        R.id.key_length_4096 -> keyLength = 4096
                    }
                }
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    // Invoked when 'Generate' button of SshKeyGenFragment clicked. Generates a
    // private and public key, then replaces the SshKeyGenFragment with a
    // ShowSshKeyFragment which displays the public key.
    private suspend fun generate(passphrase: String, comment: String) {
        binding.generate.text = getString(R.string.ssh_key_gen_generating_progress)
        val e = try {
            withContext(Dispatchers.IO) {
                val kp = KeyPair.genKeyPair(JSch(), KeyPair.RSA, keyLength)
                var file = File(requireActivity().filesDir, ".ssh_key")
                var out = FileOutputStream(file, false)
                if (passphrase.isNotEmpty()) {
                    kp?.writePrivateKey(out, passphrase.toByteArray())
                } else {
                    kp?.writePrivateKey(out)
                }
                file = File(requireActivity().filesDir, ".ssh_key.pub")
                out = FileOutputStream(file, false)
                kp?.writePublicKey(out, comment)
            }
            null
        } catch (e: Exception) {
            e.printStackTrace()
            e
        }
        val activity = requireActivity()
        binding.generate.text = getString(R.string.ssh_keygen_generating_done)
        if (e == null) {
            val df = ShowSshKeyFragment()
            df.show(requireActivity().supportFragmentManager, "public_key")
            val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
            prefs.edit { putBoolean("use_generated_key", true) }
        } else {
            MaterialAlertDialogBuilder(activity)
                .setTitle(activity.getString(R.string.error_generate_ssh_key))
                .setMessage(activity.getString(R.string.ssh_key_error_dialog_text) + e.message)
                .setPositiveButton(activity.getString(R.string.dialog_ok)) { _, _ ->
                    requireActivity().finish()
                }
                .show()
        }
        hideKeyboard()
    }

    private fun hideKeyboard() {
        val activity = activity ?: return
        val imm = activity.getSystemService<InputMethodManager>() ?: return
        var view = activity.currentFocus
        if (view == null) {
            view = View(activity)
        }
        imm.hideSoftInputFromWindow(view.windowToken, 0)
    }
}