summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMS <ms@taler.net>2023-10-17 20:49:54 +0200
committerMS <ms@taler.net>2023-10-17 20:49:54 +0200
commit8fea1754a168d3328fa764cc83c43319c73a9180 (patch)
tree5827fbde356c07c5324394e9eb278dc515f461c1
parent3e6220f36e17045e92a0f127b208bbb23508babb (diff)
downloadlibeufin-8fea1754a168d3328fa764cc83c43319c73a9180.tar.gz
libeufin-8fea1754a168d3328fa764cc83c43319c73a9180.tar.bz2
libeufin-8fea1754a168d3328fa764cc83c43319c73a9180.zip
Importing the bank keys.
Separation between downloading and accepting keys, each goes in one helper function.
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt140
1 files changed, 68 insertions, 72 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index ce10dcc6..aae917ba 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -352,24 +352,40 @@ fun preparePrivateKeys(location: String): ClientPrivateKeysFile? {
* to send to the bank.
*/
enum class KeysOrderType {
- INI, HIA, HPB
+ INI,
+ HIA,
+ HPB
}
/**
- * Parses the HPB response and stores the bank keys to disk. According to
- * the --auto-accept-keys flag marks them as accepted.
+ * Asks the user to accept the bank public keys.
+ *
+ * @param bankKeys bank public keys, in format stored on disk.
+ * @return true if the user accepted, false otherwise.
+ */
+fun askUserToAcceptKeys(bankKeys: BankPublicKeysFile): Boolean {
+ val encHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_encryption_public_key).toHexString()
+ val authHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_authentication_public_key).toHexString()
+ println("Bank has the following keys, type 'yes, accept' to accept it")
+ println("Encryption key: $encHash")
+ println("Authentication key: $authHash")
+ val userResponse: String? = readlnOrNull()
+ if (userResponse != "yes, accept")
+ return true
+ return false
+}
+
+/**
+ * Parses the HPB response and stores the bank keys as "NOT accepted" to disk.
*
* @param cfg used to get the location of the bank keys file.
* @param bankKeys bank response to the HPB message.
- * @param autoAccept whether the user gave the --auto-accept-keys CLI flag.
- * @return true if the keys were marked as accepted AND the bank keys file
- * could be written to the disk. False if even one of the previous
- * condition isn't satisfied.
+ * @return true if the keys were stored to disk (as "not accepted"),
+ * false if the storage failed or the content was invalid.
*/
private fun handleHpbResponse(
cfg: EbicsSetupConfig,
- bankKeys: EbicsKeyManagementResponseContent,
- autoAccept: Boolean
+ bankKeys: EbicsKeyManagementResponseContent
): Boolean {
val hpbBytes = bankKeys.orderData // silences compiler.
if (hpbBytes == null) {
@@ -395,29 +411,16 @@ private fun handleHpbResponse(
logger.error("Could not import bank authentication key from HPB response, detail: ${e.message}")
return false
}
-
- var areKeysAccepted = true
- if (!autoAccept) { // asks user.
- val encHash = CryptoUtil.getEbicsPublicKeyHash(encPub).toHexString()
- val authHash = CryptoUtil.getEbicsPublicKeyHash(authPub).toHexString()
- println("Bank has the following keys, type 'yes, accept' to accept it")
- println("Encryption key: $encHash")
- println("Authentication key: $authHash")
- val userResponse: String? = readlnOrNull()
- if (userResponse != "yes, accept") {
- areKeysAccepted = false
- }
- }
val json = BankPublicKeysFile(
bank_authentication_public_key = authPub,
bank_encryption_public_key = encPub,
- accepted = areKeysAccepted
+ accepted = false
)
if (!syncJsonToDisk(json, cfg.bankPublicKeysFilename)) {
logger.error("Failed to persist the bank keys to disk at: ${cfg.bankPublicKeysFilename}")
return false
}
- return areKeysAccepted
+ return true
}
/**
@@ -438,8 +441,7 @@ suspend fun doKeysRequestAndUpdateState(
cfg: EbicsSetupConfig,
privs: ClientPrivateKeysFile,
client: HttpClient,
- orderType: KeysOrderType,
- autoAcceptBankKeys: Boolean? = null
+ orderType: KeysOrderType
): Boolean {
val req = when(orderType) {
KeysOrderType.INI -> generateIniMessage(cfg, privs)
@@ -468,13 +470,7 @@ suspend fun doKeysRequestAndUpdateState(
when(orderType) {
KeysOrderType.INI -> privs.submitted_ini = true
KeysOrderType.HIA -> privs.submitted_hia = true
- KeysOrderType.HPB -> {
- if (autoAcceptBankKeys == null) {
- logger.error("Cannot do HPB without any auto accept policy.")
- return false
- }
- return handleHpbResponse(cfg, ebics, autoAcceptBankKeys)
- }
+ KeysOrderType.HPB -> return handleHpbResponse(cfg, ebics)
}
if (!syncJsonToDisk(privs, cfg.clientPrivateKeysFilename)) {
logger.error("Could not update the ${orderType.name} state on disk")
@@ -604,27 +600,12 @@ class EbicsSetup: CliktCommand() {
private val generateRegistrationPdf by option(
help = "generates the PDF with the client public keys to send to the bank"
).flag(default = false)
+ private val showAssociatedAccounts by option(
+ help = "shows which bank accounts belong to the EBICS subscriber"
+ ).flag(default = false)
/**
* This function collects the main steps of setting up an EBICS access.
- *
- * First, it loads the configuration and checks its correctness. It proceeds
- * by creating the private keys (if they weren't found) and by uploading them
- * to the bank, if they weren't before (or the --force-keys-resubmission flag
- * was given). After the successful upload, it generates a PDF with the key
- * fingerprint to let the user send it via post to the bank.
- *
- * It goes by downloading the bank keys (if they weren't before), and
- * by showing their fingerprint to the user. After the user confirms
- * them (or the --auto-accept-keys was given), the bank keys are marked
- * as accepted.
- *
- * Finally, we check that the bank hosts the bank account that is
- * set in the configuration value ACCOUNT_NUMBER. In such case, we
- * update the ACCOUNT_META_DATA file, otherwise we fail by showing
- * which bank account was offered by the bank.
- *
- * Ends with a "setup ready" message.
*/
override fun run() {
val cfg = extractConfig(this.configFile)
@@ -638,8 +619,7 @@ class EbicsSetup: CliktCommand() {
exitProcess(1)
}
val httpClient = HttpClient()
- // Privs exist. Upload their pubs if forced, or they weren't uploaded yet.
- // Whenever one branch fails, the process fails too (doKeysRequest logs the reason).
+ // Privs exist. Upload their pubs
val keysNotSub = !privsMaybe.submitted_ini || !privsMaybe.submitted_hia
runBlocking {
if ((!privsMaybe.submitted_ini) || forceKeysResubmission)
@@ -647,7 +627,7 @@ class EbicsSetup: CliktCommand() {
if ((!privsMaybe.submitted_hia) || forceKeysResubmission)
doKeysRequestAndUpdateState(cfg, privsMaybe, httpClient, KeysOrderType.HIA).apply { if (!this) exitProcess(1) }
}
- // Reloading from disk if any upload actually took place
+ // Reloading new state from disk if any upload actually took place
val haveSubmitted = forceKeysResubmission || keysNotSub
val privs = if (haveSubmitted)
loadPrivateKeysFromDisk(cfg.clientPrivateKeysFilename)
@@ -663,30 +643,37 @@ class EbicsSetup: CliktCommand() {
}
// Eject PDF if the keys were submitted for the first time, or the user asked.
if (keysNotSub || generateRegistrationPdf) makePdf(privs, cfg)
-
- // Downloading the bank keys: always fails before the PDF arrives to the bank.
- // Note: this step also asks the user about accepting the keys (according to the
- // auto-accept flag.)
- runBlocking {
- if (!doKeysRequestAndUpdateState(
- cfg,
- privs,
- httpClient,
- KeysOrderType.HPB,
- autoAcceptBankKeys = autoAcceptKeys
- )) {
- logger.error("Could not download or update the bank keys on disk.")
+ // Checking if the bank keys exist on disk.
+ val bankKeysFile = File(cfg.bankPublicKeysFilename)
+ if (!bankKeysFile.exists()) {
+ val areKeysOnDisk = runBlocking {
+ doKeysRequestAndUpdateState(
+ cfg,
+ privs,
+ httpClient,
+ KeysOrderType.HPB
+ )
+ }
+ if (!areKeysOnDisk) {
+ logger.error("Could not download bank keys. Send client keys (and/or related PDF document with --generate-registration-pdf) to the bank.")
exitProcess(1)
}
}
+ // bank keys made it to the disk, check if they're accepted.
val bankKeys = loadBankKeys(cfg.bankPublicKeysFilename)
if (bankKeys == null) {
- logger.error("Could not load the bank keys file from: ${cfg.bankPublicKeysFilename}")
+ logger.error("Although previous checks, could not load the bank keys file from: ${cfg.bankPublicKeysFilename}")
exitProcess(1)
}
if (!bankKeys.accepted) {
- logger.error("Cannot fetch bank accounts: bank keys are not accepted yet.")
- exitProcess(1)
+
+ if (autoAcceptKeys) bankKeys.accepted = true
+ else bankKeys.accepted = askUserToAcceptKeys(bankKeys)
+
+ if (bankKeys.accepted && !syncJsonToDisk(bankKeys, cfg.bankPublicKeysFilename)) {
+ logger.error("Could not set bank keys as accepted on disk.")
+ exitProcess(1)
+ }
}
// Downloading the list of owned bank account(s).
val bankAccounts = runBlocking {
@@ -709,13 +696,22 @@ class EbicsSetup: CliktCommand() {
logger.error("Bank has another IBAN for us: $foundIban, while config has: ${cfg.accountNumber}")
exitProcess(1)
}
+ // Users wants only _see_ the accounts, NOT checking values and returning here.
+ if (showAssociatedAccounts) {
+ println("Bank associates this account to the EBICS user ${cfg.ebicsUserId}: IBAN: $foundIban, BIC: $foundBic, Name: ${bankAccounts.userInfo.name}")
+ return
+ }
// No divergences were found, either because the config was right
// _or_ the bank didn't give any information. Setting the account
// metadata accordingly.
val accountMetaData = BankAccountMetadataFile(
- account_holder_iban = foundIban ?: cfg.accountNumber, // stick to config, if bank was silent.
account_holder_name = bankAccounts.userInfo.name ?: "Account holder name not given",
- bank_code = foundBic // null if bank was silent, also not mandatory to operate.
+ account_holder_iban = foundIban ?: run iban@ {
+ logger.warn("Bank did not show any IBAN for us, defaulting to the one we configured.")
+ return@iban cfg.accountNumber },
+ bank_code = foundBic ?: run bic@ {
+ logger.warn("Bank did not show any BIC for us, it remains null.")
+ return@bic null }
)
if (!syncJsonToDisk(accountMetaData, cfg.bankAccountMetadataFilename)) {
logger.error("Failed to persist bank account meta-data at: ${cfg.bankAccountMetadataFilename}")