aboutsummaryrefslogtreecommitdiff
path: root/crypto-pgp
diff options
context:
space:
mode:
Diffstat (limited to 'crypto-pgp')
-rw-r--r--crypto-pgp/api/crypto-pgp.api25
-rw-r--r--crypto-pgp/build.gradle.kts29
-rw-r--r--crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyManagerTest.kt165
-rw-r--r--crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyPairTest.kt52
-rw-r--r--crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/utils/CryptoConstants.kt14
-rw-r--r--crypto-pgp/src/androidTest/res/raw/private_key18
-rw-r--r--crypto-pgp/src/main/AndroidManifest.xml6
-rw-r--r--crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyManager.kt95
-rw-r--r--crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyPair.kt28
-rw-r--r--crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler.kt49
10 files changed, 0 insertions, 481 deletions
diff --git a/crypto-pgp/api/crypto-pgp.api b/crypto-pgp/api/crypto-pgp.api
deleted file mode 100644
index c9b2dde7..00000000
--- a/crypto-pgp/api/crypto-pgp.api
+++ /dev/null
@@ -1,25 +0,0 @@
-public final class dev/msfjarvis/aps/data/crypto/GPGKeyManager : dev/msfjarvis/aps/data/crypto/KeyManager {
- public fun <init> (Ljava/lang/String;Lkotlinx/coroutines/CoroutineDispatcher;)V
- public fun addKey (Ldev/msfjarvis/aps/data/crypto/GPGKeyPair;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public synthetic fun addKey (Ldev/msfjarvis/aps/data/crypto/KeyPair;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public fun canHandle (Ljava/lang/String;)Z
- public fun getAllKeys (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public fun getKeyById (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public fun removeKey (Ldev/msfjarvis/aps/data/crypto/GPGKeyPair;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public synthetic fun removeKey (Ldev/msfjarvis/aps/data/crypto/KeyPair;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-}
-
-public final class dev/msfjarvis/aps/data/crypto/GPGKeyPair : dev/msfjarvis/aps/data/crypto/KeyPair {
- public fun <init> (Lcom/proton/Gopenpgp/crypto/Key;)V
- public fun getKeyId ()Ljava/lang/String;
- public fun getPrivateKey ()[B
- public fun getPublicKey ()[B
-}
-
-public final class dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler : dev/msfjarvis/aps/data/crypto/CryptoHandler {
- public fun <init> ()V
- public fun canHandle (Ljava/lang/String;)Z
- public fun decrypt (Ljava/lang/String;[B[B)[B
- public fun encrypt (Ljava/lang/String;[B)[B
-}
-
diff --git a/crypto-pgp/build.gradle.kts b/crypto-pgp/build.gradle.kts
deleted file mode 100644
index 95542b1c..00000000
--- a/crypto-pgp/build.gradle.kts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-plugins {
- id("com.android.library")
- kotlin("android")
- `aps-plugin`
-}
-
-android {
- defaultConfig {
- testApplicationId = "dev.msfjarvis.aps.cryptopgp.test"
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- }
-}
-
-dependencies {
- api(projects.cryptoCommon)
- implementation(libs.androidx.annotation)
- implementation(libs.aps.gopenpgp)
- implementation(libs.dagger.hilt.core)
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.thirdparty.kotlinResult)
- androidTestImplementation(libs.bundles.testDependencies)
- androidTestImplementation(libs.kotlin.coroutines.test)
- androidTestImplementation(libs.bundles.androidTestDependencies)
-}
diff --git a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyManagerTest.kt b/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyManagerTest.kt
deleted file mode 100644
index 80a13eb5..00000000
--- a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyManagerTest.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-package dev.msfjarvis.aps.crypto
-
-import androidx.test.platform.app.InstrumentationRegistry
-import com.github.michaelbull.result.unwrap
-import com.github.michaelbull.result.unwrapError
-import com.proton.Gopenpgp.crypto.Key
-import dev.msfjarvis.aps.crypto.utils.CryptoConstants
-import dev.msfjarvis.aps.cryptopgp.test.R
-import dev.msfjarvis.aps.data.crypto.GPGKeyManager
-import dev.msfjarvis.aps.data.crypto.GPGKeyPair
-import dev.msfjarvis.aps.data.crypto.KeyManagerException
-import java.io.File
-import kotlin.test.assertEquals
-import kotlin.test.assertIs
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineDispatcher
-import kotlinx.coroutines.test.runBlockingTest
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-
-@OptIn(ExperimentalCoroutinesApi::class)
-public class GPGKeyManagerTest {
-
- private val testCoroutineDispatcher = TestCoroutineDispatcher()
- private lateinit var gpgKeyManager: GPGKeyManager
- private lateinit var key: GPGKeyPair
-
- @Before
- public fun setup() {
- gpgKeyManager = GPGKeyManager(getFilesDir().absolutePath, testCoroutineDispatcher)
- key = GPGKeyPair(Key(getKey()))
- }
-
- @After
- public fun tearDown() {
- val filesDir = getFilesDir()
- val keysDir = File(filesDir, GPGKeyManager.KEY_DIR_NAME)
-
- keysDir.deleteRecursively()
- }
-
- @Test
- public fun testAddingKey() {
- runBlockingTest {
- // Check if the key id returned is correct
- val keyId = gpgKeyManager.addKey(key).unwrap().getKeyId()
- assertEquals(CryptoConstants.KEY_ID, keyId)
-
- // Check if the keys directory have one file
- val keysDir = File(getFilesDir(), GPGKeyManager.KEY_DIR_NAME)
- assertEquals(1, keysDir.list()?.size)
-
- // Check if the file name is correct
- val keyFile = keysDir.listFiles()?.first()
- assertEquals(keyFile?.name, "$keyId.${GPGKeyManager.KEY_EXTENSION}")
- }
- }
-
- @Test
- public fun testAddingKeyWithoutReplaceFlag() {
- runBlockingTest {
- // Check adding the keys twice
- gpgKeyManager.addKey(key, false).unwrap()
- val error = gpgKeyManager.addKey(key, false).unwrapError()
-
- assertIs<KeyManagerException.KeyAlreadyExistsException>(error)
- }
- }
-
- @Test
- public fun testAddingKeyWithReplaceFlag() {
- runBlockingTest {
- // Check adding the keys twice
- gpgKeyManager.addKey(key, true).unwrap()
- val keyId = gpgKeyManager.addKey(key, true).unwrap().getKeyId()
-
- assertEquals(CryptoConstants.KEY_ID, keyId)
- }
- }
-
- @Test
- public fun testRemovingKey() {
- runBlockingTest {
- // Add key using KeyManager
- gpgKeyManager.addKey(key).unwrap()
-
- // Check if the key id returned is correct
- val keyId = gpgKeyManager.removeKey(key).unwrap().getKeyId()
- assertEquals(CryptoConstants.KEY_ID, keyId)
-
- // Check if the keys directory have 0 files
- val keysDir = File(getFilesDir(), GPGKeyManager.KEY_DIR_NAME)
- assertEquals(0, keysDir.list()?.size)
- }
- }
-
- @Test
- public fun testGetExistingKey() {
- runBlockingTest {
- // Add key using KeyManager
- gpgKeyManager.addKey(key).unwrap()
-
- // Check returned key id matches the expected id and the created key id
- val returnedKeyPair = gpgKeyManager.getKeyById(key.getKeyId()).unwrap()
- assertEquals(CryptoConstants.KEY_ID, key.getKeyId())
- assertEquals(key.getKeyId(), returnedKeyPair.getKeyId())
- }
- }
-
- @Test
- public fun testGetNonExistentKey() {
- runBlockingTest {
- // Add key using KeyManager
- gpgKeyManager.addKey(key).unwrap()
-
- val randomKeyId = "0x123456789"
-
- // Check returned key
- val error = gpgKeyManager.getKeyById(randomKeyId).unwrapError()
- assertIs<KeyManagerException.KeyNotFoundException>(error)
- assertEquals("No key found with id: $randomKeyId", error.message)
- }
- }
-
- @Test
- public fun testFindKeysWithoutAdding() {
- runBlockingTest {
- // Check returned key
- val error = gpgKeyManager.getKeyById("0x123456789").unwrapError()
- assertIs<KeyManagerException.NoKeysAvailableException>(error)
- assertEquals("No keys were found", error.message)
- }
- }
-
- @Test
- public fun testGettingAllKeys() {
- runBlockingTest {
- // TODO: Should we check for more than 1 keys?
- // Check if KeyManager returns no key
- val noKeyList = gpgKeyManager.getAllKeys().unwrap()
- assertEquals(0, noKeyList.size)
-
- // Add key using KeyManager
- gpgKeyManager.addKey(key).unwrap()
-
- // Check if KeyManager returns one key
- val singleKeyList = gpgKeyManager.getAllKeys().unwrap()
- assertEquals(1, singleKeyList.size)
- }
- }
-
- private companion object {
-
- fun getFilesDir(): File = InstrumentationRegistry.getInstrumentation().context.filesDir
-
- fun getKey(): String =
- InstrumentationRegistry.getInstrumentation()
- .context
- .resources
- .openRawResource(R.raw.private_key)
- .readBytes()
- .decodeToString()
- }
-}
diff --git a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyPairTest.kt b/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyPairTest.kt
deleted file mode 100644
index 2340d9a5..00000000
--- a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/GPGKeyPairTest.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.crypto
-
-import androidx.test.platform.app.InstrumentationRegistry
-import com.proton.Gopenpgp.crypto.Key
-import dev.msfjarvis.aps.crypto.utils.CryptoConstants
-import dev.msfjarvis.aps.cryptopgp.test.R
-import dev.msfjarvis.aps.data.crypto.GPGKeyPair
-import dev.msfjarvis.aps.data.crypto.KeyPairException
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import org.junit.Test
-
-public class GPGKeyPairTest {
-
- @Test
- public fun testIfKeyIdIsCorrect() {
- val gpgKey = Key(getKey())
- val keyPair = GPGKeyPair(gpgKey)
-
- assertEquals(CryptoConstants.KEY_ID, keyPair.getKeyId())
- }
-
- @Test
- public fun testBuildingKeyPairWithoutPrivateKey() {
- assertFailsWith<KeyPairException.PrivateKeyUnavailableException>(
- "GPGKeyPair does not have a private sub key"
- ) {
- // Get public key object from private key
- val gpgKey = Key(getKey()).toPublic()
- // Try creating a KeyPair from public key
- val keyPair = GPGKeyPair(gpgKey)
-
- keyPair.getPrivateKey()
- }
- }
-
- private companion object {
-
- fun getKey(): String =
- InstrumentationRegistry.getInstrumentation()
- .context
- .resources
- .openRawResource(R.raw.private_key)
- .readBytes()
- .decodeToString()
- }
-}
diff --git a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/utils/CryptoConstants.kt b/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/utils/CryptoConstants.kt
deleted file mode 100644
index 873f7105..00000000
--- a/crypto-pgp/src/androidTest/kotlin/dev/msfjarvis/aps/crypto/utils/CryptoConstants.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.crypto.utils
-
-internal object CryptoConstants {
- internal const val KEY_PASSPHRASE = "hunter2"
- internal const val PLAIN_TEXT = "encryption worthy content"
- internal const val KEY_NAME = "John Doe"
- internal const val KEY_EMAIL = "john.doe@example.com"
- internal const val KEY_ID = "04ace699d5b15b7e"
-}
diff --git a/crypto-pgp/src/androidTest/res/raw/private_key b/crypto-pgp/src/androidTest/res/raw/private_key
deleted file mode 100644
index 5a4f436c..00000000
--- a/crypto-pgp/src/androidTest/res/raw/private_key
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN PGP PRIVATE KEY BLOCK-----
-Version: GopenPGP 2.1.9
-Comment: https://gopenpgp.org
-
-xYYEYN+EThYJKwYBBAHaRw8BAQdAh0d9GdVyJV6KbFynPz3sHkdi5RDnKYs+l0x0
-rEOEthX+CQMIfg7BTvTTe7pgvNERA1vLXRjSxXyi7tfSV13JRnrapp7YtNUSHLVS
-PqbaLBd6+EXx7dJ9mUSUSWVga5mdtLZ/k6e+6dsygeHiJuwxfGbHnc0fSm9obiBE
-b2UgPGpvaG4uZG9lQGV4YW1wbGUuY29tPsKIBBMWCAA6BQJg34ROCRAErOaZ1bFb
-fhYhBJQ0DPsSHC5XfslyQwSs5pnVsVt+AhsDAh4BAhkBAwsJBwIVCAIiAQAAtgwB
-AOa3rnipQPsxgxvOP1V+2kD6ssiwt6BZRWwPcyfeX1h4AP9ozBYr+PSmNbam9bnq
-wgXwuQhPJeWTSgILMaiasugGCMeLBGDfhE4SCisGAQQBl1UBBQEBB0ClFQJX/L2G
-EX9ucC5mvwj3X/7aDXDFAmIpQeWYSS1negMBCgn+CQMIF1uko+Ym3thgoDWUgM5e
-MNmDG3rYkTa7h6mlhhrsYtE/GN78EJHP1ygFzOczU/YdbxSRTZCu697uPCZLWURV
-1+b66KLTMNHNaAkoFb2JC8J4BBgWCAAqBQJg34ROCRAErOaZ1bFbfhYhBJQ0DPsS
-HC5XfslyQwSs5pnVsVt+AhsMAAB1CgEApNcEivCSp0f8CnV4UCoSRRRekIbP1Ub2
-GJx6iRJR8xwA/jicDxdnl/Umfd3mWjGk04R47whiDOXdwjBmC1KVBaMH
-=Sfsa
------END PGP PRIVATE KEY BLOCK----- \ No newline at end of file
diff --git a/crypto-pgp/src/main/AndroidManifest.xml b/crypto-pgp/src/main/AndroidManifest.xml
deleted file mode 100644
index f72b702d..00000000
--- a/crypto-pgp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- ~ SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
- -->
-
-<manifest package="dev.msfjarvis.aps.cryptopgp"></manifest>
diff --git a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyManager.kt b/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyManager.kt
deleted file mode 100644
index 478d2700..00000000
--- a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyManager.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.data.crypto
-
-import androidx.annotation.VisibleForTesting
-import com.github.michaelbull.result.Result
-import com.github.michaelbull.result.runCatching
-import com.proton.Gopenpgp.crypto.Crypto
-import java.io.File
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.withContext
-
-public class GPGKeyManager(filesDir: String, private val dispatcher: CoroutineDispatcher) :
- KeyManager<GPGKeyPair> {
-
- private val keyDir = File(filesDir, KEY_DIR_NAME)
-
- override suspend fun addKey(key: GPGKeyPair, replace: Boolean): Result<GPGKeyPair, Throwable> =
- withContext(dispatcher) {
- runCatching {
- if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
- val keyFile = File(keyDir, "${key.getKeyId()}.$KEY_EXTENSION")
- if (keyFile.exists()) {
- // Check for replace flag first and if it is false, throw an error
- if (!replace) throw KeyManagerException.KeyAlreadyExistsException(key.getKeyId())
- if (!keyFile.delete()) throw KeyManagerException.KeyDeletionFailedException
- }
-
- keyFile.writeBytes(key.getPrivateKey())
-
- key
- }
- }
-
- override suspend fun removeKey(key: GPGKeyPair): Result<GPGKeyPair, Throwable> =
- withContext(dispatcher) {
- runCatching {
- if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
- val keyFile = File(keyDir, "${key.getKeyId()}.$KEY_EXTENSION")
- if (keyFile.exists()) {
- if (!keyFile.delete()) throw KeyManagerException.KeyDeletionFailedException
- }
-
- key
- }
- }
-
- override suspend fun getKeyById(id: String): Result<GPGKeyPair, Throwable> =
- withContext(dispatcher) {
- runCatching {
- if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
- val keys = keyDir.listFiles()
- if (keys.isNullOrEmpty()) throw KeyManagerException.NoKeysAvailableException
-
- for (keyFile in keys) {
- val keyPair = GPGKeyPair(Crypto.newKeyFromArmored(keyFile.readText()))
- if (keyPair.getKeyId() == id) return@runCatching keyPair
- }
-
- throw KeyManagerException.KeyNotFoundException(id)
- }
- }
-
- override suspend fun getAllKeys(): Result<List<GPGKeyPair>, Throwable> =
- withContext(dispatcher) {
- runCatching {
- if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
- val keys = keyDir.listFiles()
- if (keys.isNullOrEmpty()) return@runCatching listOf()
-
- keys.map { GPGKeyPair(Crypto.newKeyFromArmored(it.readText())) }.toList()
- }
- }
-
- override fun canHandle(fileName: String): Boolean {
- // TODO: This is a temp hack for now and in future it should check that the GPGKeyManager can
- // decrypt the file
- return fileName.endsWith(KEY_EXTENSION)
- }
-
- private fun keyDirExists(): Boolean {
- return keyDir.exists() || keyDir.mkdirs()
- }
-
- internal companion object {
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- internal const val KEY_DIR_NAME: String = "keys"
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- internal const val KEY_EXTENSION: String = "key"
- }
-}
diff --git a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyPair.kt b/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyPair.kt
deleted file mode 100644
index 2dbe8689..00000000
--- a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GPGKeyPair.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.data.crypto
-
-import com.proton.Gopenpgp.crypto.Key
-
-/** Wraps a Gopenpgp [Key] to implement [KeyPair]. */
-public class GPGKeyPair(private val key: Key) : KeyPair {
-
- init {
- if (!key.isPrivate) throw KeyPairException.PrivateKeyUnavailableException
- }
-
- override fun getPrivateKey(): ByteArray {
- return key.armor().encodeToByteArray()
- }
-
- override fun getPublicKey(): ByteArray {
- return key.armoredPublicKey.encodeToByteArray()
- }
-
- override fun getKeyId(): String {
- return key.hexKeyID
- }
-}
diff --git a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler.kt b/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler.kt
deleted file mode 100644
index 5d14b160..00000000
--- a/crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.data.crypto
-
-import com.proton.Gopenpgp.crypto.Crypto
-import com.proton.Gopenpgp.helper.Helper
-import javax.inject.Inject
-
-/** Gopenpgp backed implementation of [CryptoHandler]. */
-public class GopenpgpCryptoHandler @Inject constructor() : CryptoHandler {
-
- /**
- * Decrypt the given [ciphertext] using the given PGP [privateKey] and corresponding [passphrase].
- */
- override fun decrypt(
- privateKey: String,
- passphrase: ByteArray,
- ciphertext: ByteArray,
- ): ByteArray {
- // Decode the incoming cipher into a string and try to guess if it's armored.
- val cipherString = ciphertext.decodeToString()
- val isArmor = cipherString.startsWith("-----BEGIN PGP MESSAGE-----")
- val message =
- if (isArmor) {
- Crypto.newPGPMessageFromArmored(cipherString)
- } else {
- Crypto.newPGPMessage(ciphertext)
- }
- return Helper.decryptBinaryMessageArmored(
- privateKey,
- passphrase,
- message.armored,
- )
- }
-
- override fun encrypt(publicKey: String, plaintext: ByteArray): ByteArray {
- return Helper.encryptBinaryMessage(
- publicKey,
- plaintext,
- )
- }
-
- override fun canHandle(fileName: String): Boolean {
- return fileName.split('.').last() == "gpg"
- }
-}