build: update to openpgp-ktx 2.0 (#749)
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
f9c310e93a
commit
edc6dcda88
3 changed files with 188 additions and 203 deletions
|
@ -9,15 +9,6 @@ plugins {
|
||||||
|
|
||||||
final def keystorePropertiesFile = rootProject.file 'keystore.properties'
|
final def keystorePropertiesFile = rootProject.file 'keystore.properties'
|
||||||
|
|
||||||
final def gitHash = { ->
|
|
||||||
final def stdout = new ByteArrayOutputStream()
|
|
||||||
exec {
|
|
||||||
commandLine 'git', 'describe', '--tags'
|
|
||||||
standardOutput = stdout
|
|
||||||
}
|
|
||||||
stdout.toString().trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
static final def isSnapshot() {
|
static final def isSnapshot() {
|
||||||
return System.env['GITHUB_WORKFLOW'] != null && System.env['SNAPSHOT'] != null
|
return System.env['GITHUB_WORKFLOW'] != null && System.env['SNAPSHOT'] != null
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,175 +365,173 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
val oStream = ByteArrayOutputStream()
|
val oStream = ByteArrayOutputStream()
|
||||||
|
|
||||||
lifecycleScope.launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
api?.executeApiAsync(data, iStream, oStream, object : OpenPgpApi.IOpenPgpCallback {
|
api?.executeApiAsync(data, iStream, oStream) { result ->
|
||||||
override fun onReturn(result: Intent?) {
|
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
||||||
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
RESULT_CODE_SUCCESS -> {
|
||||||
RESULT_CODE_SUCCESS -> {
|
try {
|
||||||
try {
|
val showPassword = settings.getBoolean("show_password", true)
|
||||||
val showPassword = settings.getBoolean("show_password", true)
|
val showExtraContent = settings.getBoolean("show_extra_content", true)
|
||||||
val showExtraContent = settings.getBoolean("show_extra_content", true)
|
|
||||||
|
|
||||||
crypto_container_decrypt.visibility = View.VISIBLE
|
crypto_container_decrypt.visibility = View.VISIBLE
|
||||||
|
|
||||||
val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
|
val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
|
||||||
val entry = PasswordEntry(oStream)
|
val entry = PasswordEntry(oStream)
|
||||||
|
|
||||||
passwordEntry = entry
|
passwordEntry = entry
|
||||||
|
|
||||||
if (intent.getStringExtra("OPERATION") == "EDIT") {
|
if (intent.getStringExtra("OPERATION") == "EDIT") {
|
||||||
editPassword()
|
editPassword()
|
||||||
return
|
return@executeApiAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.password.isEmpty()) {
|
if (entry.password.isEmpty()) {
|
||||||
crypto_password_show.visibility = View.GONE
|
crypto_password_show.visibility = View.GONE
|
||||||
crypto_password_show_label.visibility = View.GONE
|
crypto_password_show_label.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
crypto_password_show.visibility = View.VISIBLE
|
crypto_password_show.visibility = View.VISIBLE
|
||||||
crypto_password_show_label.visibility = View.VISIBLE
|
crypto_password_show_label.visibility = View.VISIBLE
|
||||||
crypto_password_show.typeface = monoTypeface
|
|
||||||
crypto_password_show.text = entry.password
|
|
||||||
}
|
|
||||||
crypto_password_show.typeface = monoTypeface
|
crypto_password_show.typeface = monoTypeface
|
||||||
crypto_password_show.text = entry.password
|
crypto_password_show.text = entry.password
|
||||||
|
}
|
||||||
|
crypto_password_show.typeface = monoTypeface
|
||||||
|
crypto_password_show.text = entry.password
|
||||||
|
|
||||||
crypto_password_toggle_show.visibility = if (showPassword) View.GONE else View.VISIBLE
|
crypto_password_toggle_show.visibility = if (showPassword) View.GONE else View.VISIBLE
|
||||||
crypto_password_show.transformationMethod = if (showPassword) {
|
crypto_password_show.transformationMethod = if (showPassword) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
HoldToShowPasswordTransformation(
|
HoldToShowPasswordTransformation(
|
||||||
crypto_password_toggle_show,
|
crypto_password_toggle_show,
|
||||||
Runnable { crypto_password_show.text = entry.password }
|
Runnable { crypto_password_show.text = entry.password }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.hasExtraContent()) {
|
if (entry.hasExtraContent()) {
|
||||||
crypto_extra_show.typeface = monoTypeface
|
crypto_extra_show.typeface = monoTypeface
|
||||||
crypto_extra_show.text = entry.extraContent
|
crypto_extra_show.text = entry.extraContent
|
||||||
|
|
||||||
if (showExtraContent) {
|
if (showExtraContent) {
|
||||||
crypto_extra_show_layout.visibility = View.VISIBLE
|
|
||||||
crypto_extra_toggle_show.visibility = View.GONE
|
|
||||||
crypto_extra_show.transformationMethod = null
|
|
||||||
} else {
|
|
||||||
crypto_extra_show_layout.visibility = View.GONE
|
|
||||||
crypto_extra_toggle_show.visibility = View.VISIBLE
|
|
||||||
crypto_extra_toggle_show.setOnCheckedChangeListener { _, _ ->
|
|
||||||
crypto_extra_show.text = entry.extraContent
|
|
||||||
}
|
|
||||||
|
|
||||||
crypto_extra_show.transformationMethod = object : PasswordTransformationMethod() {
|
|
||||||
override fun getTransformation(source: CharSequence, view: View): CharSequence {
|
|
||||||
return if (crypto_extra_toggle_show.isChecked) source else super.getTransformation(source, view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.hasUsername()) {
|
|
||||||
crypto_username_show.visibility = View.VISIBLE
|
|
||||||
crypto_username_show_label.visibility = View.VISIBLE
|
|
||||||
crypto_copy_username.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username!!) }
|
|
||||||
crypto_username_show.typeface = monoTypeface
|
|
||||||
crypto_username_show.text = entry.username
|
|
||||||
} else {
|
|
||||||
crypto_username_show.visibility = View.GONE
|
|
||||||
crypto_username_show_label.visibility = View.GONE
|
|
||||||
crypto_copy_username.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.hasTotp() || entry.hasHotp()) {
|
|
||||||
crypto_extra_show_layout.visibility = View.VISIBLE
|
crypto_extra_show_layout.visibility = View.VISIBLE
|
||||||
crypto_extra_show.typeface = monoTypeface
|
crypto_extra_toggle_show.visibility = View.GONE
|
||||||
crypto_extra_show.text = entry.extraContent
|
crypto_extra_show.transformationMethod = null
|
||||||
|
} else {
|
||||||
|
crypto_extra_show_layout.visibility = View.GONE
|
||||||
|
crypto_extra_toggle_show.visibility = View.VISIBLE
|
||||||
|
crypto_extra_toggle_show.setOnCheckedChangeListener { _, _ ->
|
||||||
|
crypto_extra_show.text = entry.extraContent
|
||||||
|
}
|
||||||
|
|
||||||
crypto_otp_show.visibility = View.VISIBLE
|
crypto_extra_show.transformationMethod = object : PasswordTransformationMethod() {
|
||||||
crypto_otp_show_label.visibility = View.VISIBLE
|
override fun getTransformation(source: CharSequence, view: View): CharSequence {
|
||||||
crypto_copy_otp.visibility = View.VISIBLE
|
return if (crypto_extra_toggle_show.isChecked) source else super.getTransformation(source, view)
|
||||||
|
|
||||||
if (entry.hasTotp()) {
|
|
||||||
crypto_copy_otp.setOnClickListener {
|
|
||||||
copyOtpToClipBoard(
|
|
||||||
Otp.calculateCode(
|
|
||||||
entry.totpSecret,
|
|
||||||
Date().time / (1000 * entry.totpPeriod),
|
|
||||||
entry.totpAlgorithm,
|
|
||||||
entry.digits)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
crypto_otp_show.text =
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.hasUsername()) {
|
||||||
|
crypto_username_show.visibility = View.VISIBLE
|
||||||
|
crypto_username_show_label.visibility = View.VISIBLE
|
||||||
|
crypto_copy_username.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username!!) }
|
||||||
|
crypto_username_show.typeface = monoTypeface
|
||||||
|
crypto_username_show.text = entry.username
|
||||||
|
} else {
|
||||||
|
crypto_username_show.visibility = View.GONE
|
||||||
|
crypto_username_show_label.visibility = View.GONE
|
||||||
|
crypto_copy_username.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.hasTotp() || entry.hasHotp()) {
|
||||||
|
crypto_extra_show_layout.visibility = View.VISIBLE
|
||||||
|
crypto_extra_show.typeface = monoTypeface
|
||||||
|
crypto_extra_show.text = entry.extraContent
|
||||||
|
|
||||||
|
crypto_otp_show.visibility = View.VISIBLE
|
||||||
|
crypto_otp_show_label.visibility = View.VISIBLE
|
||||||
|
crypto_copy_otp.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
if (entry.hasTotp()) {
|
||||||
|
crypto_copy_otp.setOnClickListener {
|
||||||
|
copyOtpToClipBoard(
|
||||||
Otp.calculateCode(
|
Otp.calculateCode(
|
||||||
entry.totpSecret,
|
entry.totpSecret,
|
||||||
Date().time / (1000 * entry.totpPeriod),
|
Date().time / (1000 * entry.totpPeriod),
|
||||||
entry.totpAlgorithm,
|
entry.totpAlgorithm,
|
||||||
entry.digits)
|
entry.digits)
|
||||||
} else {
|
)
|
||||||
// we only want to calculate and show HOTP if the user requests it
|
}
|
||||||
crypto_copy_otp.setOnClickListener {
|
crypto_otp_show.text =
|
||||||
if (settings.getBoolean("hotp_remember_check", false)) {
|
Otp.calculateCode(
|
||||||
if (settings.getBoolean("hotp_remember_choice", false)) {
|
entry.totpSecret,
|
||||||
calculateAndCommitHotp(entry)
|
Date().time / (1000 * entry.totpPeriod),
|
||||||
} else {
|
entry.totpAlgorithm,
|
||||||
calculateHotp(entry)
|
entry.digits)
|
||||||
}
|
} else {
|
||||||
|
// we only want to calculate and show HOTP if the user requests it
|
||||||
|
crypto_copy_otp.setOnClickListener {
|
||||||
|
if (settings.getBoolean("hotp_remember_check", false)) {
|
||||||
|
if (settings.getBoolean("hotp_remember_choice", false)) {
|
||||||
|
calculateAndCommitHotp(entry)
|
||||||
} else {
|
} else {
|
||||||
// show a dialog asking permission to update the HOTP counter in the entry
|
calculateHotp(entry)
|
||||||
val checkInflater = LayoutInflater.from(this@PgpActivity)
|
}
|
||||||
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
|
} else {
|
||||||
val rememberCheck: CheckBox =
|
// show a dialog asking permission to update the HOTP counter in the entry
|
||||||
checkLayout.findViewById(R.id.hotp_remember_checkbox)
|
val checkInflater = LayoutInflater.from(this@PgpActivity)
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(this@PgpActivity)
|
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
|
||||||
dialogBuilder.setView(checkLayout)
|
val rememberCheck: CheckBox =
|
||||||
dialogBuilder.setMessage(R.string.dialog_update_body)
|
checkLayout.findViewById(R.id.hotp_remember_checkbox)
|
||||||
.setCancelable(false)
|
val dialogBuilder = MaterialAlertDialogBuilder(this@PgpActivity)
|
||||||
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
|
dialogBuilder.setView(checkLayout)
|
||||||
run {
|
dialogBuilder.setMessage(R.string.dialog_update_body)
|
||||||
calculateAndCommitHotp(entry)
|
.setCancelable(false)
|
||||||
if (rememberCheck.isChecked) {
|
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
|
||||||
settings.edit {
|
run {
|
||||||
putBoolean("hotp_remember_check", true)
|
calculateAndCommitHotp(entry)
|
||||||
putBoolean("hotp_remember_choice", true)
|
if (rememberCheck.isChecked) {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
|
|
||||||
run {
|
|
||||||
calculateHotp(entry)
|
|
||||||
settings.edit {
|
settings.edit {
|
||||||
putBoolean("hotp_remember_check", true)
|
putBoolean("hotp_remember_check", true)
|
||||||
putBoolean("hotp_remember_choice", false)
|
putBoolean("hotp_remember_choice", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val updateDialog = dialogBuilder.create()
|
}
|
||||||
updateDialog.setTitle(R.string.dialog_update_title)
|
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
|
||||||
updateDialog.show()
|
run {
|
||||||
}
|
calculateHotp(entry)
|
||||||
|
settings.edit {
|
||||||
|
putBoolean("hotp_remember_check", true)
|
||||||
|
putBoolean("hotp_remember_choice", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val updateDialog = dialogBuilder.create()
|
||||||
|
updateDialog.setTitle(R.string.dialog_update_title)
|
||||||
|
updateDialog.show()
|
||||||
}
|
}
|
||||||
crypto_otp_show.setText(R.string.hotp_pending)
|
|
||||||
}
|
}
|
||||||
crypto_otp_show.typeface = monoTypeface
|
crypto_otp_show.setText(R.string.hotp_pending)
|
||||||
} else {
|
|
||||||
crypto_otp_show.visibility = View.GONE
|
|
||||||
crypto_otp_show_label.visibility = View.GONE
|
|
||||||
crypto_copy_otp.visibility = View.GONE
|
|
||||||
}
|
}
|
||||||
|
crypto_otp_show.typeface = monoTypeface
|
||||||
if (settings.getBoolean("copy_on_decrypt", true)) {
|
} else {
|
||||||
copyPasswordToClipBoard()
|
crypto_otp_show.visibility = View.GONE
|
||||||
}
|
crypto_otp_show_label.visibility = View.GONE
|
||||||
} catch (e: Exception) {
|
crypto_copy_otp.visibility = View.GONE
|
||||||
e(e) { "An Exception occurred" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.getBoolean("copy_on_decrypt", true)) {
|
||||||
|
copyPasswordToClipBoard()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e(e) { "An Exception occurred" }
|
||||||
}
|
}
|
||||||
RESULT_CODE_USER_INTERACTION_REQUIRED -> handleUserInteractionRequest(result, REQUEST_DECRYPT)
|
|
||||||
RESULT_CODE_ERROR -> handleError(result)
|
|
||||||
}
|
}
|
||||||
|
RESULT_CODE_USER_INTERACTION_REQUIRED -> handleUserInteractionRequest(result, REQUEST_DECRYPT)
|
||||||
|
RESULT_CODE_ERROR -> handleError(result)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,48 +589,46 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
api?.executeApiAsync(data, iStream, oStream, object : OpenPgpApi.IOpenPgpCallback {
|
api?.executeApiAsync(data, iStream, oStream) { result ->
|
||||||
override fun onReturn(result: Intent?) {
|
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
||||||
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
RESULT_CODE_SUCCESS -> {
|
||||||
RESULT_CODE_SUCCESS -> {
|
try {
|
||||||
try {
|
// TODO This might fail, we should check that the write is successful
|
||||||
// TODO This might fail, we should check that the write is successful
|
val file = File(path)
|
||||||
val file = File(path)
|
val outputStream = FileUtils.openOutputStream(file)
|
||||||
val outputStream = FileUtils.openOutputStream(file)
|
outputStream.write(oStream.toByteArray())
|
||||||
outputStream.write(oStream.toByteArray())
|
outputStream.close()
|
||||||
outputStream.close()
|
|
||||||
|
|
||||||
val returnIntent = Intent()
|
val returnIntent = Intent()
|
||||||
returnIntent.putExtra("CREATED_FILE", path)
|
returnIntent.putExtra("CREATED_FILE", path)
|
||||||
returnIntent.putExtra("NAME", editName)
|
returnIntent.putExtra("NAME", editName)
|
||||||
returnIntent.putExtra("LONG_NAME", getLongName(fullPath, repoPath, editName!!))
|
returnIntent.putExtra("LONG_NAME", getLongName(fullPath, repoPath, editName!!))
|
||||||
|
|
||||||
// if coming from decrypt screen->edit button
|
// if coming from decrypt screen->edit button
|
||||||
if (intent.getBooleanExtra("fromDecrypt", false)) {
|
if (intent.getBooleanExtra("fromDecrypt", false)) {
|
||||||
returnIntent.putExtra("OPERATION", "EDIT")
|
returnIntent.putExtra("OPERATION", "EDIT")
|
||||||
returnIntent.putExtra("needCommit", true)
|
returnIntent.putExtra("needCommit", true)
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldGeneratePassword) {
|
|
||||||
val directoryStructure =
|
|
||||||
AutofillPreferences.directoryStructure(applicationContext)
|
|
||||||
val entry = PasswordEntry(content)
|
|
||||||
returnIntent.putExtra("PASSWORD", entry.password)
|
|
||||||
val username = PasswordEntry(content).username
|
|
||||||
?: directoryStructure.getUsernameFor(file)
|
|
||||||
returnIntent.putExtra("USERNAME", username)
|
|
||||||
}
|
|
||||||
|
|
||||||
setResult(RESULT_OK, returnIntent)
|
|
||||||
finish()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e(e) { "An Exception occurred" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldGeneratePassword) {
|
||||||
|
val directoryStructure =
|
||||||
|
AutofillPreferences.directoryStructure(applicationContext)
|
||||||
|
val entry = PasswordEntry(content)
|
||||||
|
returnIntent.putExtra("PASSWORD", entry.password)
|
||||||
|
val username = PasswordEntry(content).username
|
||||||
|
?: directoryStructure.getUsernameFor(file)
|
||||||
|
returnIntent.putExtra("USERNAME", username)
|
||||||
|
}
|
||||||
|
|
||||||
|
setResult(RESULT_OK, returnIntent)
|
||||||
|
finish()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e(e) { "An Exception occurred" }
|
||||||
}
|
}
|
||||||
RESULT_CODE_ERROR -> handleError(result)
|
|
||||||
}
|
}
|
||||||
|
RESULT_CODE_ERROR -> handleError(result)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,31 +711,29 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
val data = receivedIntent ?: Intent()
|
val data = receivedIntent ?: Intent()
|
||||||
data.action = OpenPgpApi.ACTION_GET_KEY_IDS
|
data.action = OpenPgpApi.ACTION_GET_KEY_IDS
|
||||||
lifecycleScope.launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
api?.executeApiAsync(data, null, null, object : OpenPgpApi.IOpenPgpCallback {
|
api?.executeApiAsync(data, null, null) { result ->
|
||||||
override fun onReturn(result: Intent?) {
|
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
||||||
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
RESULT_CODE_SUCCESS -> {
|
||||||
RESULT_CODE_SUCCESS -> {
|
try {
|
||||||
try {
|
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
|
||||||
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
|
?: LongArray(0)
|
||||||
?: LongArray(0)
|
val keys = ids.map { it.toString() }.toSet()
|
||||||
val keys = ids.map { it.toString() }.toSet()
|
|
||||||
|
|
||||||
// use Long
|
// use Long
|
||||||
settings.edit { putStringSet("openpgp_key_ids_set", keys) }
|
settings.edit { putStringSet("openpgp_key_ids_set", keys) }
|
||||||
|
|
||||||
showSnackbar("PGP keys selected")
|
showSnackbar("PGP keys selected")
|
||||||
|
|
||||||
setResult(RESULT_OK)
|
setResult(RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e(e) { "An Exception occurred" }
|
e(e) { "An Exception occurred" }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RESULT_CODE_USER_INTERACTION_REQUIRED -> handleUserInteractionRequest(result, REQUEST_KEY_ID)
|
|
||||||
RESULT_CODE_ERROR -> handleError(result)
|
|
||||||
}
|
}
|
||||||
|
RESULT_CODE_USER_INTERACTION_REQUIRED -> handleUserInteractionRequest(result, REQUEST_KEY_ID)
|
||||||
|
RESULT_CODE_ERROR -> handleError(result)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ ext.deps = [
|
||||||
jsch: 'com.jcraft:jsch:0.1.55',
|
jsch: 'com.jcraft:jsch:0.1.55',
|
||||||
jgit: 'org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r',
|
jgit: 'org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r',
|
||||||
leakcanary: 'com.squareup.leakcanary:leakcanary-android:2.2',
|
leakcanary: 'com.squareup.leakcanary:leakcanary-android:2.2',
|
||||||
openpgp_ktx: 'com.github.android-password-store:openpgp-ktx:1.2.0',
|
openpgp_ktx: 'com.github.android-password-store:openpgp-ktx:2.0.0',
|
||||||
// The library is updated every two weeks to include the most recent version of the Public
|
// The library is updated every two weeks to include the most recent version of the Public
|
||||||
// suffix list. Its API is expected to remain stable for the foreseeable future, and thus
|
// suffix list. Its API is expected to remain stable for the foreseeable future, and thus
|
||||||
// a reference to the latest version is warranted.
|
// a reference to the latest version is warranted.
|
||||||
|
|
Loading…
Reference in a new issue