libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

CliTest.kt (6254B)


      1 /*
      2  * This file is part of LibEuFin.
      3  * Copyright (C) 2023-2025 Taler Systems S.A.
      4 
      5  * LibEuFin is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU Affero General Public License as
      7  * published by the Free Software Foundation; either version 3, or
      8  * (at your option) any later version.
      9 
     10  * LibEuFin is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
     13  * Public License for more details.
     14 
     15  * You should have received a copy of the GNU Affero General Public
     16  * License along with LibEuFin; see the file COPYING.  If not, see
     17  * <http://www.gnu.org/licenses/>
     18  */
     19 
     20 import com.github.ajalt.clikt.core.CliktCommand
     21 import com.github.ajalt.clikt.testing.test
     22 import tech.libeufin.common.crypto.CryptoUtil
     23 import tech.libeufin.common.asUtf8
     24 import tech.libeufin.nexus.*
     25 import tech.libeufin.ebics.*
     26 import tech.libeufin.nexus.cli.LibeufinNexus
     27 import tech.libeufin.ebisync.cli.LibeufinEbisync
     28 import java.io.ByteArrayOutputStream
     29 import java.io.PrintStream
     30 import kotlin.io.path.*
     31 import kotlin.test.Test
     32 import kotlin.test.assertEquals
     33 
     34 val nexusCmd = LibeufinNexus()
     35 val ebisyncCmd = LibeufinEbisync()
     36 
     37 fun CliktCommand.testErr(cmd: String, msg: String) {
     38     val prevOut = System.err
     39     val tmpOut = ByteArrayOutputStream()
     40     System.setErr(PrintStream(tmpOut))
     41     val result = test(cmd)
     42     System.setErr(prevOut)
     43     val tmpStr = tmpOut.asUtf8()
     44     println(tmpStr)
     45     assertEquals(1, result.statusCode, "'$cmd' should have failed")
     46     val line = tmpStr.substringAfterLast(" - ").trimEnd('\n')
     47     println(line)
     48     assertEquals(msg, line)
     49 }
     50 
     51 class CliTest {
     52     /** Test error format related to the keying process */
     53     @Test
     54     fun keys() {
     55         val nexusCmds = listOf("ebics-submit", "ebics-fetch")
     56         val nexusAllCmds = listOf("ebics-submit", "ebics-fetch", "ebics-setup")
     57         val ebiSyncCmds = listOf("fetch")
     58         val ebiSyncAllCmds = listOf("fetch", "setup")
     59         val conf = "conf/cli.conf"
     60         val nexusCfg = nexusConfig(Path(conf))
     61         val cfg = nexusCfg.ebics
     62         val clientKeysPath = cfg.clientPrivateKeysPath
     63         val bankKeysPath = cfg.bankPublicKeysPath
     64         clientKeysPath.parent!!.createParentDirectories()
     65         clientKeysPath.parent!!.toFile().setWritable(true)
     66         bankKeysPath.parent!!.createDirectories()
     67 
     68         fun checkCmds(msg: String) {
     69             for (cmd in listOf("ebics-submit", "ebics-fetch")) {
     70                 nexusCmd.testErr("$cmd -c $conf", msg.replace("SETUPCMD", "libeufin-nexus ebics-setup"))
     71             }
     72             for (cmd in listOf("fetch")) {
     73                 ebisyncCmd.testErr("$cmd -c $conf", msg.replace("SETUPCMD", "libeufin-ebisync setup"))
     74             }
     75         }
     76         fun checkAllCmds(msg: String) {
     77             for (cmd in listOf("ebics-submit", "ebics-fetch", "ebics-setup")) {
     78                 nexusCmd.testErr("$cmd -c $conf", msg)
     79             }
     80             for (cmd in listOf("fetch", "setup")) {
     81                 ebisyncCmd.testErr("$cmd -c $conf", msg)
     82             }
     83         }
     84         
     85         // Missing client keys
     86         clientKeysPath.deleteIfExists()
     87         checkCmds("Missing client private keys file at '$clientKeysPath', run 'SETUPCMD' first")
     88         // Empty client file
     89         clientKeysPath.createFile()
     90         checkAllCmds("Could not decode client private keys at '$clientKeysPath': Expected start of the object '{', but had 'EOF' instead at path: $\nJSON input: ")
     91         // Bad client json
     92         clientKeysPath.writeText("CORRUPTION", Charsets.UTF_8)
     93         checkAllCmds("Could not decode client private keys at '$clientKeysPath': Unexpected JSON token at offset 0: Expected start of the object '{', but had 'C' instead at path: $\nJSON input: CORRUPTION")
     94         // Missing permission
     95         clientKeysPath.toFile().setReadable(false)
     96         if (!clientKeysPath.isReadable()) { // Skip if root
     97             checkAllCmds("Could not read client private keys at '$clientKeysPath': permission denied")
     98         }
     99         // Unfinished client
    100         persistClientKeys(generateNewKeys(), clientKeysPath)
    101         checkCmds("Unsubmitted client private keys, run 'SETUPCMD' first")
    102 
    103         // Missing bank keys
    104         persistClientKeys(generateNewKeys().apply {
    105             submitted_hia = true
    106             submitted_ini = true
    107         }, clientKeysPath)
    108         bankKeysPath.deleteIfExists()
    109         checkCmds("Missing bank public keys at '$bankKeysPath', run 'SETUPCMD' first")
    110         // Empty bank file
    111         bankKeysPath.createFile()
    112         checkAllCmds("Could not decode bank public keys at '$bankKeysPath': Expected start of the object '{', but had 'EOF' instead at path: $\nJSON input: ")
    113         // Bad bank json
    114         bankKeysPath.writeText("CORRUPTION", Charsets.UTF_8)
    115         checkAllCmds("Could not decode bank public keys at '$bankKeysPath': Unexpected JSON token at offset 0: Expected start of the object '{', but had 'C' instead at path: $\nJSON input: CORRUPTION")
    116         // Missing permission
    117         bankKeysPath.toFile().setReadable(false)
    118         if (!bankKeysPath.isReadable()) { // Skip if root
    119             checkAllCmds("Could not read bank public keys at '$bankKeysPath': permission denied")
    120         }
    121         // Unfinished bank
    122         persistBankKeys(BankPublicKeysFile(
    123             bank_authentication_public_key = CryptoUtil.genRSAPublic(2048),
    124             bank_encryption_public_key = CryptoUtil.genRSAPublic(2048),
    125             accepted = false
    126         ), bankKeysPath)
    127         checkCmds("Unaccepted bank public keys, run 'SETUPCMD' until accepting the bank keys")
    128 
    129         // Missing permission
    130         clientKeysPath.deleteIfExists()
    131         clientKeysPath.parent!!.toFile().setWritable(false)
    132         if (!clientKeysPath.parent!!.isWritable()) { // Skip if root
    133             nexusCmd.testErr("ebics-setup -c $conf", "Could not write client private keys at '$clientKeysPath': permission denied on '${clientKeysPath.parent}'")
    134             ebisyncCmd.testErr("setup -c $conf", "Could not write client private keys at '$clientKeysPath': permission denied on '${clientKeysPath.parent}'")
    135         }
    136     }
    137 }