libeufin

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

commit 19b8afec701f83903e01ca03a6a431616edc5e3f
parent f8ae684976d2391ba991fd52cafd75fb20a6fe2c
Author: Antoine A <>
Date:   Fri,  6 Sep 2024 14:21:33 +0200

common: renaming and clean code

Diffstat:
Mbank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt | 18+++++++++---------
Mbank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt | 4++--
Mbank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt | 32++++++++++++++++----------------
Mbank/src/main/kotlin/tech/libeufin/bank/cli/CreateAccount.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/cli/DbInit.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt | 104++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mbank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt | 24++++++++++++------------
Mbank/src/main/kotlin/tech/libeufin/bank/db/ExchangeDAO.kt | 26+++++++++++++-------------
Mbank/src/main/kotlin/tech/libeufin/bank/db/TanDAO.kt | 20++++++++++----------
Mbank/src/main/kotlin/tech/libeufin/bank/db/TokenDAO.kt | 20++++++++++----------
Mbank/src/main/kotlin/tech/libeufin/bank/db/TransactionDAO.kt | 28++++++++++++++--------------
Mbank/src/main/kotlin/tech/libeufin/bank/db/WithdrawalDAO.kt | 18+++++++++---------
Mbank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/params.kt | 6+++---
Mbank/src/test/kotlin/AmountTest.kt | 4++--
Mbank/src/test/kotlin/CoreBankApiTest.kt | 8++++----
Mbank/src/test/kotlin/DatabaseTest.kt | 2+-
Mbank/src/test/kotlin/bench.kt | 6+++---
Mbank/src/test/kotlin/helpers.kt | 10+++++-----
Adatabase-versioning/libeufin-bank-0008.sql | 29+++++++++++++++++++++++++++++
Mdatabase-versioning/libeufin-bank-procedures.sql | 72++++++++++++++++++++++++++++++++++++------------------------------------
Mdatabase-versioning/libeufin-conversion-setup.sql | 14+++++++-------
Mdatabase-versioning/libeufin-nexus-0007.sql | 11+++++++++++
Mdatabase-versioning/libeufin-nexus-procedures.sql | 76++++++++++++++++++++++++++++++++++++++--------------------------------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt | 15+++++----------
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsFetch.kt | 4++--
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSubmit.kt | 2+-
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/InitiatePayment.kt | 10+++-------
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/Testing.kt | 9++-------
Mnexus/src/main/kotlin/tech/libeufin/nexus/db/Database.kt | 2+-
Mnexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt | 38+++++++++++++++++++-------------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/db/InitiatedDAO.kt | 58+++++++++++++++++++++++++++++-----------------------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt | 56++++++++++++++++++++++++++++----------------------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt | 12++++++------
Mnexus/src/test/kotlin/DatabaseTest.kt | 6+++---
Mnexus/src/test/kotlin/IngestionTest.kt | 34+++++++++++++++++-----------------
Mnexus/src/test/kotlin/Iso20022Test.kt | 24++++++++++++------------
Mnexus/src/test/kotlin/bench.kt | 12++++++------
Mnexus/src/test/kotlin/helpers.kt | 17++++++-----------
Mtestbench/src/test/kotlin/IntegrationTest.kt | 8++++----
Mtestbench/src/test/kotlin/MigrationTest.kt | 3+++
43 files changed, 438 insertions(+), 414 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt @@ -288,7 +288,7 @@ data class BearerToken( val isRefreshable: Boolean, val creationTime: Instant, val expirationTime: Instant, - val login: String + val username: String ) @Serializable diff --git a/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt @@ -118,7 +118,7 @@ private fun Routing.coreBankTokenApi(db: Database, cfg: BankConfig) { } } if (!db.token.create( - login = username, + username = username, content = token.raw, creationTime = creationTime, expirationTime = expirationTimestamp, @@ -208,7 +208,7 @@ suspend fun createAccount( ) suspend fun doDb(internalPayto: Payto) = db.account.create( - login = req.username, + username = req.username, name = req.name, email = req.contact_data?.email?.get(), phone = req.contact_data?.phone?.get(), @@ -260,7 +260,7 @@ suspend fun patchAccount( db: Database, cfg: BankConfig, req: AccountReconfiguration, - login: String, + username: String, isAdmin: Boolean, is2fa: Boolean, channel: TanChannel? = null, @@ -268,7 +268,7 @@ suspend fun patchAccount( ): AccountPatchResult { req.debit_threshold?.run { cfg.checkRegionalCurrency(this) } - if (login == "admin" && req.is_public == true) + if (username == "admin" && req.is_public == true) throw conflict( "'admin' account cannot be public", TalerErrorCode.END @@ -279,7 +279,7 @@ suspend fun patchAccount( } return db.account.reconfig( - login = login, + username = username, name = req.name, cashoutPayto = req.cashout_payto_uri, email = req.contact_data?.email ?: Option.None, @@ -306,7 +306,7 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) { "Insufficient admin funds to grant bonus", TalerErrorCode.BANK_UNALLOWED_DEBIT ) - AccountCreationResult.LoginReuse -> throw conflict( + AccountCreationResult.UsernameReuse -> throw conflict( "Account username reuse '${req.username}'", TalerErrorCode.BANK_REGISTER_USERNAME_REUSE ) @@ -624,7 +624,7 @@ private fun Routing.coreBankCashoutApi(db: Database, ctx: BankConfig) = conditio ctx.checkFiatCurrency(req.amount_credit) val res = db.cashout.create( - login = username, + username = username, requestUid = req.request_uid, amountDebit = req.amount_debit, amountCredit = req.amount_credit, @@ -703,7 +703,7 @@ private fun Routing.coreBankTanApi(db: Database, ctx: BankConfig) { val id = call.longPath("CHALLENGE_ID") val res = db.tan.send( id = id, - login = username, + username = username, code = Tan.genCode(), timestamp = Instant.now(), retryCounter = TAN_RETRY_COUNTER, @@ -767,7 +767,7 @@ private fun Routing.coreBankTanApi(db: Database, ctx: BankConfig) { val code = req.tan.removePrefix("T-") val res = db.tan.solve( id = id, - login = username, + username = username, code = code, timestamp = Instant.now() ) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt @@ -51,7 +51,7 @@ fun Routing.wireGatewayApi(db: Database, ctx: BankConfig) { ctx.checkRegionalCurrency(req.amount) val res = db.exchange.transfer( req = req, - login = username, + username = username, timestamp = Instant.now() ) when (res) { @@ -160,7 +160,7 @@ fun Routing.wireGatewayApi(db: Database, ctx: BankConfig) { amount = amount, debitAccount = debitAccount, subject = subject, - login = username, + username = username, timestamp = timestamp, metadata = metadata ) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt @@ -48,7 +48,7 @@ suspend inline fun <reified B> ApplicationCall.respondChallenge( val json = Json.encodeToString(kotlinx.serialization.serializer<B>(), body) val code = Tan.genCode() val id = db.tan.new( - login = username, + username = username, op = op, body = json, code = code, diff --git a/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt @@ -65,18 +65,18 @@ val ApplicationCall.authToken: ByteArray? get() = attributes.getOrNull(AUTH_TOKE fun Route.authAdmin(db: Database, pwCrypto: PwCrypto, scope: TokenScope, enforce: Boolean = true, callback: Route.() -> Unit): Route = intercept(callback) { if (enforce) { - val login = context.authenticateBankRequest(db, pwCrypto, scope) - if (login != "admin") { + val username = context.authenticateBankRequest(db, pwCrypto, scope) + if (username != "admin") { throw unauthorized("Only administrator allowed") } context.attributes.put(AUTH_IS_ADMIN, true) } else { - val login = try { + val username = try { context.authenticateBankRequest(db, pwCrypto, scope) } catch (e: Exception) { null } - context.attributes.put(AUTH_IS_ADMIN, login == "admin") + context.attributes.put(AUTH_IS_ADMIN, username == "admin") } } @@ -91,16 +91,16 @@ fun Route.authAdmin(db: Database, pwCrypto: PwCrypto, scope: TokenScope, enforce **/ fun Route.auth(db: Database, pwCrypto: PwCrypto ,scope: TokenScope, allowAdmin: Boolean = false, requireAdmin: Boolean = false, callback: Route.() -> Unit): Route = intercept(callback) { - val authLogin = context.authenticateBankRequest(db, pwCrypto, scope) - if (requireAdmin && authLogin != "admin") { + val authUsername = context.authenticateBankRequest(db, pwCrypto, scope) + if (requireAdmin && authUsername != "admin") { throw unauthorized("Only administrator allowed") } else { - val hasRight = authLogin == username || (allowAdmin && authLogin == "admin") + val hasRight = authUsername == username || (allowAdmin && authUsername == "admin") if (!hasRight) { - throw unauthorized("Customer $authLogin have no right on $username account") + throw unauthorized("Customer $authUsername have no right on $username account") } } - context.attributes.put(AUTH_IS_ADMIN, authLogin == "admin") + context.attributes.put(AUTH_IS_ADMIN, authUsername == "admin") } /** @@ -108,7 +108,7 @@ fun Route.auth(db: Database, pwCrypto: PwCrypto ,scope: TokenScope, allowAdmin: * in the Authorization header. * The allowed schemes are either 'Basic' or 'Bearer'. * - * Returns the authenticated customer login. + * Returns the authenticated customer username. */ private suspend fun ApplicationCall.authenticateBankRequest(db: Database, pwCrypto: PwCrypto, requiredScope: TokenScope): String { val header = request.headers[HttpHeaders.Authorization] @@ -137,18 +137,18 @@ private suspend fun ApplicationCall.authenticateBankRequest(db: Database, pwCryp /** * Performs the HTTP Basic Authentication. * - * Returns the authenticated customer login + * Returns the authenticated customer username */ private suspend fun doBasicAuth(db: Database, encoded: String, pwCrypto: PwCrypto): String { val decoded = String(encoded.decodeBase64(), Charsets.UTF_8) - val (login, plainPassword) = decoded.splitOnce(":") ?: throw badRequest( + val (username, plainPassword) = decoded.splitOnce(":") ?: throw badRequest( "Malformed Basic auth credentials found in the Authorization header", TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED ) - return when (db.account.checkPassword(login, plainPassword, pwCrypto)) { + return when (db.account.checkPassword(username, plainPassword, pwCrypto)) { CheckPasswordResult.UnknownAccount -> throw unauthorized("Unknown account") CheckPasswordResult.PasswordMismatch -> throw unauthorized("Bad password") - CheckPasswordResult.Success -> login + CheckPasswordResult.Success -> username } } @@ -164,7 +164,7 @@ fun validScope(required: TokenScope, scope: TokenScope): Boolean { /** * Performs the secret-token HTTP Bearer Authentication. * - * Returns the authenticated customer login + * Returns the authenticated customer username */ private suspend fun ApplicationCall.doTokenAuth( db: Database, @@ -196,5 +196,5 @@ private suspend fun ApplicationCall.doTokenAuth( attributes.put(AUTH_TOKEN, decoded) - return token.login + return token.username } \ No newline at end of file diff --git a/bank/src/main/kotlin/tech/libeufin/bank/cli/CreateAccount.kt b/bank/src/main/kotlin/tech/libeufin/bank/cli/CreateAccount.kt @@ -101,7 +101,7 @@ class CreateAccount : CliktCommand( when (val result = createAccount(db, cfg, req, true)) { AccountCreationResult.BonusBalanceInsufficient -> throw Exception("Insufficient admin funds to grant bonus") - AccountCreationResult.LoginReuse -> + AccountCreationResult.UsernameReuse -> throw Exception("Account username reuse '${req.username}'") AccountCreationResult.PayToReuse -> throw Exception("Bank internalPayToUri reuse") diff --git a/bank/src/main/kotlin/tech/libeufin/bank/cli/DbInit.kt b/bank/src/main/kotlin/tech/libeufin/bank/cli/DbInit.kt @@ -49,7 +49,7 @@ class DbInit : CliktCommand("Initialize the libeufin-bank database", name = "dbi val res = createAdminAccount(db, cfg) when (res) { AccountCreationResult.BonusBalanceInsufficient -> {} - AccountCreationResult.LoginReuse -> {} + AccountCreationResult.UsernameReuse -> {} AccountCreationResult.PayToReuse -> throw Exception("Failed to create admin's account") is AccountCreationResult.Success -> diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt @@ -30,14 +30,14 @@ class AccountDAO(private val db: Database) { /** Result status of account creation */ sealed interface AccountCreationResult { data class Success(val payto: String): AccountCreationResult - data object LoginReuse: AccountCreationResult + data object UsernameReuse: AccountCreationResult data object PayToReuse: AccountCreationResult data object BonusBalanceInsufficient: AccountCreationResult } /** Create new account */ suspend fun create( - login: String, + username: String, password: String, name: String, email: String?, @@ -61,15 +61,15 @@ class AccountDAO(private val db: Database) { AND email IS NOT DISTINCT FROM ? AND phone IS NOT DISTINCT FROM ? AND cashout_payto IS NOT DISTINCT FROM ? - AND (NOT ? OR internal_payto_uri=?) + AND (NOT ? OR internal_payto=?) AND is_public=? AND is_taler_exchange=? AND tan_channel IS NOT DISTINCT FROM ?::tan_enum - ,internal_payto_uri, name + ,internal_payto, name FROM customers JOIN bank_accounts ON customer_id=owning_customer_id - WHERE login=? + WHERE username=? """) { // TODO check max debt and min checkout ? setString(1, name) @@ -81,11 +81,11 @@ class AccountDAO(private val db: Database) { setBoolean(7, isPublic) setBoolean(8, isTalerExchange) setString(9, tanChannel?.name) - setString(10, login) + setString(10, username) oneOrNull { Pair( pwCrypto.checkpw(password, it.getString(1)).match && it.getBoolean(2), - it.getBankPayto("internal_payto_uri", "name", ctx) + it.getBankPayto("internal_payto", "name", ctx) ) } } @@ -94,7 +94,7 @@ class AccountDAO(private val db: Database) { if (idempotent.first) { AccountCreationResult.Success(idempotent.second) } else { - AccountCreationResult.LoginReuse + AccountCreationResult.UsernameReuse } } else { if (internalPayto is IbanPayto) @@ -114,7 +114,7 @@ class AccountDAO(private val db: Database) { val customerId = conn.withStatement(""" INSERT INTO customers ( - login + username ,password_hash ,name ,email @@ -125,7 +125,7 @@ class AccountDAO(private val db: Database) { RETURNING customer_id """ ) { - setString(1, login) + setString(1, username) setString(2, pwCrypto.hashpw(password)) setString(3, name) setString(4, email) @@ -137,7 +137,7 @@ class AccountDAO(private val db: Database) { conn.withStatement(""" INSERT INTO bank_accounts( - internal_payto_uri + internal_payto ,owning_customer_id ,is_public ,is_taler_exchange @@ -194,9 +194,9 @@ class AccountDAO(private val db: Database) { TanRequired } - /** Delete account [login] */ + /** Delete account [username] */ suspend fun delete( - login: String, + username: String, is2fa: Boolean ): AccountDeletionResult = db.serializable( """ @@ -207,7 +207,7 @@ class AccountDAO(private val db: Database) { FROM account_delete(?,?,?) """ ) { - setString(1, login) + setString(1, username) setLong(2, Instant.now().micros()) setBoolean(3, is2fa) one { @@ -232,9 +232,9 @@ class AccountDAO(private val db: Database) { data object Success: AccountPatchResult } - /** Change account [login] information */ + /** Change account [username] information */ suspend fun reconfig( - login: String, + username: String, name: String?, cashoutPayto: Option<IbanPayto?>, phone: Option<String?>, @@ -277,9 +277,9 @@ class AccountDAO(private val db: Database) { FROM customers JOIN bank_accounts ON customer_id=owning_customer_id - WHERE login=? AND deleted_at IS NULL + WHERE username=? AND deleted_at IS NULL """) { - setString(1, login) + setString(1, username) oneOrNull { CurrentAccount( id = it.getLong("customer_id"), @@ -407,9 +407,9 @@ class AccountDAO(private val db: Database) { Success } - /** Change account [login] password to [newPw] if current match [oldPw] */ + /** Change account [username] password to [newPw] if current match [oldPw] */ suspend fun reconfigPassword( - login: String, + username: String, newPw: String, oldPw: String?, is2fa: Boolean, @@ -417,10 +417,10 @@ class AccountDAO(private val db: Database) { ): AccountPatchAuthResult = db.serializableTransaction { conn -> val (customerId, currentPwh, tanRequired) = conn.withStatement(""" SELECT customer_id, password_hash, (NOT ? AND tan_channel IS NOT NULL) - FROM customers WHERE login=? AND deleted_at IS NULL + FROM customers WHERE username=? AND deleted_at IS NULL """) { setBoolean(1, is2fa) - setString(2, login) + setString(2, username) oneOrNull { Triple(it.getLong(1), it.getString(2), it.getBoolean(3)) } ?: return@serializableTransaction AccountPatchAuthResult.UnknownAccount @@ -448,13 +448,13 @@ class AccountDAO(private val db: Database) { Success } - /** Check password of account [login] against [pw], rehashing it if outdated */ - suspend fun checkPassword(login: String, pw: String, pwCrypto: PwCrypto): CheckPasswordResult { + /** Check password of account [username] against [pw], rehashing it if outdated */ + suspend fun checkPassword(username: String, pw: String, pwCrypto: PwCrypto): CheckPasswordResult { // Get user current password hash val info = db.serializable( - "SELECT customer_id, password_hash FROM customers WHERE login=? AND deleted_at IS NULL" + "SELECT customer_id, password_hash FROM customers WHERE username=? AND deleted_at IS NULL" ) { - setString(1, login) + setString(1, username) oneOrNull { Pair(it.getLong(1), it.getString(2)) } @@ -482,31 +482,31 @@ class AccountDAO(private val db: Database) { return CheckPasswordResult.Success } - /** Get bank info of account [login] */ - suspend fun bankInfo(login: String, ctx: BankPaytoCtx): BankInfo? = db.serializable( + /** Get bank info of account [username] */ + suspend fun bankInfo(username: String, ctx: BankPaytoCtx): BankInfo? = db.serializable( """ SELECT bank_account_id - ,internal_payto_uri + ,internal_payto ,name ,is_taler_exchange FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login=? + WHERE username=? """ ) { - setString(1, login) + setString(1, username) oneOrNull { BankInfo( - payto = it.getBankPayto("internal_payto_uri", "name", ctx), + payto = it.getBankPayto("internal_payto", "name", ctx), isTalerExchange = it.getBoolean("is_taler_exchange"), bankAccountId = it.getLong("bank_account_id") ) } } - /** Get data of account [login] */ - suspend fun get(login: String, ctx: BankPaytoCtx): AccountData? = db.serializable( + /** Get data of account [username] */ + suspend fun get(username: String, ctx: BankPaytoCtx): AccountData? = db.serializable( """ SELECT name @@ -514,7 +514,7 @@ class AccountDAO(private val db: Database) { ,phone ,tan_channel ,cashout_payto - ,internal_payto_uri + ,internal_payto ,(balance).val AS balance_val ,(balance).frac AS balance_frac ,has_debt @@ -531,10 +531,10 @@ class AccountDAO(private val db: Database) { FROM customers JOIN bank_accounts ON customer_id=owning_customer_id - WHERE login=? + WHERE username=? """ ) { - setString(1, login) + setString(1, username) oneOrNull { AccountData( name = it.getString("name"), @@ -544,7 +544,7 @@ class AccountDAO(private val db: Database) { ), tan_channel = it.getOptEnum<TanChannel>("tan_channel"), cashout_payto_uri = it.getString("cashout_payto"), - payto_uri = it.getBankPayto("internal_payto_uri", "name", ctx), + payto_uri = it.getBankPayto("internal_payto", "name", ctx), balance = Balance( amount = it.getAmount("balance", db.bankCurrency), credit_debit_indicator = @@ -573,20 +573,20 @@ class AccountDAO(private val db: Database) { (balance).val AS balance_val, (balance).frac AS balance_frac, has_debt, - internal_payto_uri, - login, + internal_payto, + username, is_taler_exchange, name, bank_account_id FROM bank_accounts JOIN customers ON owning_customer_id = customer_id WHERE is_public=true AND - ${if (params.loginFilter != null) "name LIKE ? AND" else ""} + ${if (params.usernameFilter != null) "name LIKE ? AND" else ""} deleted_at IS NULL AND """, { - if (params.loginFilter != null) { - setString(1, params.loginFilter) + if (params.usernameFilter != null) { + setString(1, params.usernameFilter) 1 } else { 0 @@ -594,9 +594,9 @@ class AccountDAO(private val db: Database) { } ) { PublicAccount( - username = it.getString("login"), + username = it.getString("username"), row_id = it.getLong("bank_account_id"), - payto_uri = it.getBankPayto("internal_payto_uri", "name", ctx), + payto_uri = it.getBankPayto("internal_payto", "name", ctx), balance = Balance( amount = it.getAmount("balance", db.bankCurrency), credit_debit_indicator = if (it.getBoolean("has_debt")) { @@ -616,7 +616,7 @@ class AccountDAO(private val db: Database) { "bank_account_id", """ SELECT - login, + username, name, (balance).val AS balance_val, (balance).frac AS balance_frac, @@ -627,7 +627,7 @@ class AccountDAO(private val db: Database) { ,(min_cashout).frac AS min_cashout_frac ,is_public ,is_taler_exchange - ,internal_payto_uri + ,internal_payto ,bank_account_id ,CASE WHEN deleted_at IS NOT NULL THEN 'deleted' @@ -635,11 +635,11 @@ class AccountDAO(private val db: Database) { END as status FROM bank_accounts JOIN customers ON owning_customer_id = customer_id - WHERE ${if (params.loginFilter != null) "name LIKE ? AND" else ""} + WHERE ${if (params.usernameFilter != null) "name LIKE ? AND" else ""} """, { - if (params.loginFilter != null) { - setString(1, params.loginFilter) + if (params.usernameFilter != null) { + setString(1, params.usernameFilter) 1 } else { 0 @@ -647,7 +647,7 @@ class AccountDAO(private val db: Database) { } ) { AccountMinimalData( - username = it.getString("login"), + username = it.getString("username"), row_id = it.getLong("bank_account_id"), name = it.getString("name"), balance = Balance( @@ -662,7 +662,7 @@ class AccountDAO(private val db: Database) { min_cashout = it.getOptAmount("min_cashout", db.bankCurrency), is_public = it.getBoolean("is_public"), is_taler_exchange = it.getBoolean("is_taler_exchange"), - payto_uri = it.getBankPayto("internal_payto_uri", "name", ctx), + payto_uri = it.getBankPayto("internal_payto", "name", ctx), status = it.getEnum("status") ) } diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt @@ -41,7 +41,7 @@ class CashoutDAO(private val db: Database) { /** Create a new cashout operation */ suspend fun create( - login: String, + username: String, requestUid: ShortHashCode, amountDebit: TalerAmount, amountCredit: TalerAmount, @@ -63,7 +63,7 @@ class CashoutDAO(private val db: Database) { FROM cashout_create(?,?,(?,?)::taler_amount,(?,?)::taler_amount,?,?,?) """ ) { - setString(1, login) + setString(1, username) setBytes(2, requestUid.raw) setLong(3, amountDebit.value) setInt(4, amountDebit.frac) @@ -87,8 +87,8 @@ class CashoutDAO(private val db: Database) { } } - /** Get status of cashout operation [id] owned by [login] */ - suspend fun get(id: Long, login: String): CashoutStatusResponse? = db.serializable( + /** Get status of cashout operation [id] owned by [username] */ + suspend fun get(id: Long, username: String): CashoutStatusResponse? = db.serializable( """ SELECT (amount_debit).val as amount_debit_val @@ -107,11 +107,11 @@ class CashoutDAO(private val db: Database) { JOIN bank_accounts ON bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id LEFT JOIN bank_account_transactions ON local_transaction=bank_transaction_id - WHERE cashout_id=? AND login=? + WHERE cashout_id=? AND username=? """ ) { setLong(1, id) - setString(2, login) + setString(2, username) oneOrNull { CashoutStatusResponse( status = CashoutStatus.confirmed, @@ -132,7 +132,7 @@ class CashoutDAO(private val db: Database) { /** Get a page of all cashout operations */ suspend fun pageAll(params: PageParams): List<GlobalCashoutInfo> = db.page(params, "cashout_id", """ - SELECT cashout_id, login + SELECT cashout_id, username FROM cashout_operations JOIN bank_accounts ON bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id @@ -140,24 +140,24 @@ class CashoutDAO(private val db: Database) { """) { GlobalCashoutInfo( cashout_id = it.getLong("cashout_id"), - username = it.getString("login"), + username = it.getString("username"), status = CashoutStatus.confirmed ) } - /** Get a page of all cashout operations owned by [login] */ - suspend fun pageForUser(params: PageParams, login: String): List<CashoutInfo> = + /** Get a page of all cashout operations owned by [username] */ + suspend fun pageForUser(params: PageParams, username: String): List<CashoutInfo> = db.page(params, "cashout_id", """ SELECT cashout_id FROM cashout_operations WHERE bank_account=( SELECT bank_account_id FROM bank_accounts JOIN customers ON owning_customer_id=customer_id - WHERE deleted_at IS NULL AND login = ? + WHERE deleted_at IS NULL AND username = ? ) AND """, bind = { - setString(1, login) + setString(1, username) 1 } ) { diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/ExchangeDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/ExchangeDAO.kt @@ -37,7 +37,7 @@ class ExchangeDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,type ,reserve_pub @@ -53,14 +53,14 @@ class ExchangeDAO(private val db: Database) { row_id = it.getLong("bank_transaction_id"), date = it.getTalerTimestamp("transaction_date"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getBankPayto("debtor_payto_uri", "debtor_name", ctx), + debit_account = it.getBankPayto("debtor_payto", "debtor_name", ctx), reserve_pub = EddsaPublicKey(it.getBytes("reserve_pub")), ) TalerIncomingType.kyc -> IncomingKycAuthTransaction( row_id = it.getLong("bank_transaction_id"), date = it.getTalerTimestamp("transaction_date"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getBankPayto("debtor_payto_uri", "debtor_name", ctx), + debit_account = it.getBankPayto("debtor_payto", "debtor_name", ctx), account_pub = EddsaPublicKey(it.getBytes("account_pub")), ) TalerIncomingType.wad -> throw UnsupportedOperationException() @@ -79,7 +79,7 @@ class ExchangeDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,creditor_payto_uri + ,creditor_payto ,creditor_name ,wtid ,exchange_base_url @@ -92,7 +92,7 @@ class ExchangeDAO(private val db: Database) { row_id = it.getLong("bank_transaction_id"), date = it.getTalerTimestamp("transaction_date"), amount = it.getAmount("amount", db.bankCurrency), - credit_account = it.getBankPayto("creditor_payto_uri", "creditor_name", ctx), + credit_account = it.getBankPayto("creditor_payto", "creditor_name", ctx), wtid = ShortHashCode(it.getBytes("wtid")), exchange_base_url = it.getString("exchange_base_url") ) @@ -113,7 +113,7 @@ class ExchangeDAO(private val db: Database) { /** Perform a Taler transfer */ suspend fun transfer( req: TransferRequest, - login: String, + username: String, timestamp: Instant ): TransferResult = db.serializable( """ @@ -143,7 +143,7 @@ class ExchangeDAO(private val db: Database) { setInt(5, req.amount.frac) setString(6, req.exchange_base_url.url) setString(7, req.credit_account.canonical) - setString(8, login) + setString(8, username) setLong(9, timestamp.micros()) one { @@ -175,7 +175,7 @@ class ExchangeDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,creditor_payto_uri + ,creditor_payto ,creditor_name FROM taler_exchange_outgoing JOIN bank_account_transactions ON bank_transaction=bank_transaction_id @@ -191,7 +191,7 @@ class ExchangeDAO(private val db: Database) { amount = it.getAmount("amount", db.bankCurrency), origin_exchange_url = it.getString("exchange_base_url"), wtid = ShortHashCode(it.getBytes("wtid")), - credit_account = it.getBankPayto("creditor_payto_uri", "creditor_name", ctx), + credit_account = it.getBankPayto("creditor_payto", "creditor_name", ctx), timestamp = it.getTalerTimestamp("transaction_date"), ) } @@ -211,7 +211,7 @@ class ExchangeDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,creditor_payto_uri + ,creditor_payto ,creditor_name FROM taler_exchange_outgoing JOIN bank_account_transactions ON bank_transaction=bank_transaction_id @@ -226,7 +226,7 @@ class ExchangeDAO(private val db: Database) { row_id = it.getLong("bank_transaction_id"), status = TransferStatusState.success, amount = it.getAmount("amount", db.bankCurrency), - credit_account = it.getBankPayto("creditor_payto_uri", "creditor_name", ctx), + credit_account = it.getBankPayto("creditor_payto", "creditor_name", ctx), timestamp = it.getTalerTimestamp("transaction_date"), ) } @@ -248,7 +248,7 @@ class ExchangeDAO(private val db: Database) { amount: TalerAmount, debitAccount: Payto, subject: String, - login: String, + username: String, timestamp: Instant, metadata: TalerIncomingMetadata ): AddIncomingResult = db.serializable( @@ -274,7 +274,7 @@ class ExchangeDAO(private val db: Database) { setLong(3, amount.value) setInt(4, amount.frac) setString(5, debitAccount.canonical) - setString(6, login) + setString(6, username) setLong(7, timestamp.micros()) setString(8, metadata.type.name) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/TanDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/TanDAO.kt @@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit class TanDAO(private val db: Database) { /** Create new TAN challenge */ suspend fun new( - login: String, + username: String, op: Operation, body: String, code: String, @@ -50,7 +50,7 @@ class TanDAO(private val db: Database) { setLong(4, timestamp.micros()) setLong(5, TimeUnit.MICROSECONDS.convert(validityPeriod)) setInt(6, retryCounter) - setString(7, login) + setString(7, username) setString(8, channel?.name) setString(9, info) oneOrNull { @@ -67,7 +67,7 @@ class TanDAO(private val db: Database) { /** Request TAN challenge transmission */ suspend fun send( id: Long, - login: String, + username: String, code: String, timestamp: Instant, retryCounter: Int, @@ -76,7 +76,7 @@ class TanDAO(private val db: Database) { "SELECT out_no_op, out_tan_code, out_tan_channel, out_tan_info FROM tan_challenge_send(?,?,?,?,?,?)" ) { setLong(1, id) - setString(2, login) + setString(2, username) setString(3, code) setLong(4, timestamp.micros()) setLong(5, TimeUnit.MICROSECONDS.convert(validityPeriod)) @@ -119,7 +119,7 @@ class TanDAO(private val db: Database) { /** Solve TAN challenge */ suspend fun solve( id: Long, - login: String, + username: String, code: String, timestamp: Instant ) = db.serializable( @@ -131,7 +131,7 @@ class TanDAO(private val db: Database) { """ ) { setLong(1, id) - setString(2, login) + setString(2, username) setString(3, code) setLong(4, timestamp.micros()) one { @@ -156,22 +156,22 @@ class TanDAO(private val db: Database) { val info: String? ) - /** Get a solved TAN challenge [id] for account [login] and [op] */ + /** Get a solved TAN challenge [id] for account [username] and [op] */ suspend fun challenge( id: Long, - login: String, + username: String, op: Operation ) = db.serializable( """ SELECT body, tan_challenges.tan_channel, tan_info FROM tan_challenges JOIN customers ON customer=customer_id - WHERE challenge_id=? AND op=?::op_enum AND login=? AND deleted_at IS NULL + WHERE challenge_id=? AND op=?::op_enum AND username=? AND deleted_at IS NULL """ ) { setLong(1, id) setString(2, op.name) - setString(3, login) + setString(3, username) oneOrNull { Challenge( body = it.getString("body"), diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/TokenDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/TokenDAO.kt @@ -30,9 +30,9 @@ import java.time.Instant /** Data access logic for auth tokens */ class TokenDAO(private val db: Database) { - /** Create new token for [login] */ + /** Create new token for [username] */ suspend fun create( - login: String, + username: String, content: ByteArray, creationTime: Instant, expirationTime: Instant, @@ -52,7 +52,7 @@ class TokenDAO(private val db: Database) { last_access ) VALUES ( ?,?,?,?::token_scope_enum, - (SELECT customer_id FROM customers WHERE login=? AND deleted_at IS NULL), + (SELECT customer_id FROM customers WHERE username=? AND deleted_at IS NULL), ?,?,? ) """ @@ -61,7 +61,7 @@ class TokenDAO(private val db: Database) { setLong(2, creationTime.micros()) setLong(3, expirationTime.micros()) setString(4, scope.name) - setString(5, login) + setString(5, username) setBoolean(6, isRefreshable) setString(7, description) setLong(8, creationTime.micros()) @@ -78,7 +78,7 @@ class TokenDAO(private val db: Database) { RETURNING creation_time, expiration_time, - login, + username, scope, is_refreshable """ @@ -89,7 +89,7 @@ class TokenDAO(private val db: Database) { BearerToken( creationTime = it.getLong("creation_time").asInstant(), expirationTime = it.getLong("expiration_time").asInstant(), - login = it.getString("login"), + username = it.getString("username"), scope = it.getEnum("scope"), isRefreshable = it.getBoolean("is_refreshable") ) @@ -104,8 +104,8 @@ class TokenDAO(private val db: Database) { execute() } - /** Get a page of all tokens of [login] accounts */ - suspend fun page(params: PageParams, login: String): List<TokenInfo> + /** Get a page of all tokens of [username] accounts */ + suspend fun page(params: PageParams, username: String): List<TokenInfo> = db.page( params, "bearer_token_id", @@ -120,11 +120,11 @@ class TokenDAO(private val db: Database) { bearer_token_id FROM bearer_tokens WHERE - bank_customer=(SELECT customer_id FROM customers WHERE deleted_at IS NULL AND login = ?) + bank_customer=(SELECT customer_id FROM customers WHERE deleted_at IS NULL AND username = ?) AND """, { - setString(1, login) + setString(1, username) 1 } ) { diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/TransactionDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/TransactionDAO.kt @@ -169,13 +169,13 @@ class TransactionDAO(private val db: Database) { } } - /** Get transaction [rowId] owned by [login] */ - suspend fun get(rowId: Long, login: String, ctx: BankPaytoCtx): BankAccountTransactionInfo? = db.serializable( + /** Get transaction [rowId] owned by [username] */ + suspend fun get(rowId: Long, username: String, ctx: BankPaytoCtx): BankAccountTransactionInfo? = db.serializable( """ SELECT - creditor_payto_uri + creditor_payto ,creditor_name - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,subject ,(amount).val AS amount_val @@ -186,15 +186,15 @@ class TransactionDAO(private val db: Database) { FROM bank_account_transactions JOIN bank_accounts ON bank_account_transactions.bank_account_id=bank_accounts.bank_account_id JOIN customers ON customer_id=owning_customer_id - WHERE bank_transaction_id=? AND login=? + WHERE bank_transaction_id=? AND username=? """ ) { setLong(1, rowId) - setString(2, login) + setString(2, username) oneOrNull { BankAccountTransactionInfo( - creditor_payto_uri = it.getBankPayto("creditor_payto_uri", "creditor_name", ctx), - debtor_payto_uri = it.getBankPayto("debtor_payto_uri", "debtor_name", ctx), + creditor_payto_uri = it.getBankPayto("creditor_payto", "creditor_name", ctx), + debtor_payto_uri = it.getBankPayto("debtor_payto", "debtor_name", ctx), amount = it.getAmount("amount", db.bankCurrency), direction = it.getEnum("direction"), subject = it.getString("subject"), @@ -216,9 +216,9 @@ class TransactionDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,debtor_payto_uri + ,debtor_payto ,debtor_name - ,creditor_payto_uri + ,creditor_payto ,creditor_name ,subject ,direction @@ -227,8 +227,8 @@ class TransactionDAO(private val db: Database) { BankAccountTransactionInfo( row_id = it.getLong("bank_transaction_id"), date = it.getTalerTimestamp("transaction_date"), - creditor_payto_uri = it.getBankPayto("creditor_payto_uri", "creditor_name", ctx), - debtor_payto_uri = it.getBankPayto("debtor_payto_uri", "debtor_name", ctx), + creditor_payto_uri = it.getBankPayto("creditor_payto", "creditor_name", ctx), + debtor_payto_uri = it.getBankPayto("debtor_payto", "debtor_name", ctx), amount = it.getAmount("amount", db.bankCurrency), subject = it.getString("subject"), direction = it.getEnum("direction") @@ -248,7 +248,7 @@ class TransactionDAO(private val db: Database) { ,transaction_date ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,subject FROM bank_account_transactions WHERE direction='credit' AND @@ -257,7 +257,7 @@ class TransactionDAO(private val db: Database) { row_id = it.getLong("bank_transaction_id"), date = it.getTalerTimestamp("transaction_date"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getBankPayto("debtor_payto_uri", "debtor_name", ctx), + debit_account = it.getBankPayto("debtor_payto", "debtor_name", ctx), subject = it.getString("subject") ) } diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/WithdrawalDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/WithdrawalDAO.kt @@ -45,7 +45,7 @@ class WithdrawalDAO(private val db: Database) { /** Create a new withdrawal operation */ suspend fun create( - login: String, + username: String, uuid: UUID, amount: TalerAmount?, suggested_amount: TalerAmount?, @@ -68,7 +68,7 @@ class WithdrawalDAO(private val db: Database) { ); """ ) { - setString(1, login) + setString(1, username) setObject(2, uuid) var id = 3 if (amount != null) { @@ -207,7 +207,7 @@ class WithdrawalDAO(private val db: Database) { /** Confirm withdrawal operation [uuid] */ suspend fun confirm( - login: String, + username: String, uuid: UUID, timestamp: Instant, is2fa: Boolean, @@ -227,7 +227,7 @@ class WithdrawalDAO(private val db: Database) { FROM confirm_taler_withdrawal(?,?,?,?,(?,?)::taler_amount,(?,?)::taler_amount,(?,?)::taler_amount); """ ) { - setString(1, login) + setString(1, username) setObject(2, uuid) setLong(3, timestamp.micros()) setBoolean(4, is2fa) @@ -254,7 +254,7 @@ class WithdrawalDAO(private val db: Database) { /** Get withdrawal operation [uuid] linked account username */ suspend fun getUsername(uuid: UUID): String? = db.serializable( """ - SELECT login + SELECT username FROM taler_withdrawal_operations JOIN bank_accounts ON wallet_bank_account=bank_account_id JOIN customers ON customer_id=owning_customer_id @@ -318,7 +318,7 @@ class WithdrawalDAO(private val db: Database) { ,confirmation_done ,reserve_pub ,selected_exchange_payto - ,login + ,username FROM taler_withdrawal_operations JOIN bank_accounts ON wallet_bank_account=bank_account_id JOIN customers ON customer_id=owning_customer_id @@ -331,7 +331,7 @@ class WithdrawalDAO(private val db: Database) { status = it.getEnum("status"), amount = it.getOptAmount("amount", db.bankCurrency), suggested_amount = it.getOptAmount("suggested_amount", db.bankCurrency), - username = it.getString("login"), + username = it.getString("username"), selected_exchange_account = it.getString("selected_exchange_payto"), selected_reserve_pub = it.getBytes("reserve_pub")?.run(::EddsaPublicKey) ) @@ -363,7 +363,7 @@ class WithdrawalDAO(private val db: Database) { ,selection_done ,aborted ,confirmation_done - ,internal_payto_uri + ,internal_payto ,reserve_pub ,selected_exchange_payto ,(max_amount).val as max_amount_val @@ -386,7 +386,7 @@ class WithdrawalDAO(private val db: Database) { selection_done = it.getBoolean("selection_done"), transfer_done = it.getBoolean("confirmation_done"), aborted = it.getBoolean("aborted"), - sender_wire = it.getString("internal_payto_uri"), + sender_wire = it.getString("internal_payto"), confirm_transfer_url = null, suggested_exchange = null, selected_exchange_account = it.getString("selected_exchange_payto"), diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt @@ -96,7 +96,7 @@ suspend fun createAdminAccount(db: Database, cfg: BankConfig, pw: String? = null } return db.account.create( - login = "admin", + username = "admin", password = pwStr, name = "Bank administrator", internalPayto = payto, diff --git a/bank/src/main/kotlin/tech/libeufin/bank/params.kt b/bank/src/main/kotlin/tech/libeufin/bank/params.kt @@ -83,12 +83,12 @@ data class MonitorParams( } data class AccountParams( - val page: PageParams, val loginFilter: String? + val page: PageParams, val usernameFilter: String? ) { companion object { fun extract(params: Parameters): AccountParams { - val loginFilter = params["filter_name"]?.run { "%$this%" } - return AccountParams(PageParams.extract(params), loginFilter) + val usernameFilter = params["filter_name"]?.run { "%$this%" } + return AccountParams(PageParams.extract(params), usernameFilter) } } } diff --git a/bank/src/test/kotlin/AmountTest.kt b/bank/src/test/kotlin/AmountTest.kt @@ -27,13 +27,13 @@ class AmountTest { // Test amount computation in db @Test fun computationTest() = bankSetup { db -> db.conn { conn -> - conn.execSQLUpdate("UPDATE libeufin_bank.bank_accounts SET balance.val = 100000 WHERE internal_payto_uri = '${customerPayto.canonical}'") + conn.execSQLUpdate("UPDATE libeufin_bank.bank_accounts SET balance.val = 100000 WHERE internal_payto = '${customerPayto.canonical}'") val stmt = conn.prepareStatement(""" UPDATE libeufin_bank.bank_accounts SET balance = (?, ?)::taler_amount ,has_debt = ? ,max_debt = (?, ?)::taler_amount - WHERE internal_payto_uri = '${merchantPayto.canonical}' + WHERE internal_payto = '${merchantPayto.canonical}' """) suspend fun routine( balance: TalerAmount, diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt @@ -40,7 +40,7 @@ class CoreBankSecurityTest { fun passwordUpdate() = bankSetup { db -> suspend fun currentHash(): String { return db.serializable( - "SELECT password_hash FROM customers WHERE login='customer'" + "SELECT password_hash FROM customers WHERE username='customer'" ) { one { it.getString(1) @@ -53,7 +53,7 @@ class CoreBankSecurityTest { val pwh = CryptoUtil.hashStringSHA256(password).encodeBase64() val hash = "sha256\$$pwh" db.serializable( - "UPDATE customers SET password_hash=? WHERE login='customer'" + "UPDATE customers SET password_hash=? WHERE username='customer'" ) { setString(1, hash) executeUpdate() @@ -406,7 +406,7 @@ class CoreBankAccountsApiTest { } }.assertConflict(TalerErrorCode.END) - // Testing login conflict + // Testing username conflict client.post("/accounts") { json(req) { "name" to "Foo" @@ -625,7 +625,7 @@ class CoreBankAccountsApiTest { .assertChallenge() .assertNoContent() - // Check account can no longer login + // Check account can no longer username client.delete("/accounts/customer/token") { headers[HttpHeaders.Authorization] = "Bearer $token" }.assertUnauthorized() diff --git a/bank/src/test/kotlin/DatabaseTest.kt b/bank/src/test/kotlin/DatabaseTest.kt @@ -45,7 +45,7 @@ class DatabaseTest { // Create admin account assertIs<AccountCreationResult.Success>(createAdminAccount(db, ctx)) // Checking idempotency - assertEquals(AccountCreationResult.LoginReuse, createAdminAccount(db, ctx)) + assertEquals(AccountCreationResult.UsernameReuse, createAdminAccount(db, ctx)) } @Test diff --git a/bank/src/test/kotlin/bench.kt b/bank/src/test/kotlin/bench.kt @@ -51,10 +51,10 @@ class Bench { val token64 = ByteArray(64) conn.genData(amount, sequenceOf( - "customers(login, name, password_hash, cashout_payto)" to { + "customers(username, name, password_hash, cashout_payto)" to { "account_$it\t$password\tMr n°$it\t$unknownPayto\n" }, - "bank_accounts(internal_payto_uri, owning_customer_id, is_public)" to { + "bank_accounts(internal_payto, owning_customer_id, is_public)" to { "payto://x-taler-bank/localhost/account_$it\t${it+skipAccount}\t${it%3==0}\n" }, "bearer_tokens(content, creation_time, expiration_time, scope, is_refreshable, bank_customer, description, last_access)" to { @@ -62,7 +62,7 @@ class Bench { val hex = token32.rand().encodeHex() "\\\\x$hex\t0\t0\treadonly\tfalse\t$account\t\\N\t0\n" }, - "bank_account_transactions(creditor_payto_uri, creditor_name, debtor_payto_uri, debtor_name, subject, amount, transaction_date, direction, bank_account_id)" to { + "bank_account_transactions(creditor_payto, creditor_name, debtor_payto, debtor_name, subject, amount, transaction_date, direction, bank_account_id)" to { val account = if (it > mid) customerAccount else it+4 "$unknownPayto\tcreditor_name\t$unknownPayto\tdebtor_name\tsubject\t(42,0)\t0\tcredit\t$exchangeAccount\n" + "$unknownPayto\tcreditor_name\t$unknownPayto\tdebtor_name\tsubject\t(42,0)\t0\tdebit\t$account\n" diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt @@ -81,7 +81,7 @@ fun bankSetup( // Creating the exchange and merchant accounts first. val bonus = TalerAmount.zero("KUDOS") assertIs<AccountCreationResult.Success>(db.account.create( - login = "merchant", + username = "merchant", password = "merchant-password", name = "Merchant", internalPayto = merchantPayto, @@ -99,7 +99,7 @@ fun bankSetup( pwCrypto = cfg.pwCrypto )) assertIs<AccountCreationResult.Success>(db.account.create( - login = "exchange", + username = "exchange", password = "exchange-password", name = "Exchange", internalPayto = exchangePayto, @@ -117,7 +117,7 @@ fun bankSetup( pwCrypto = cfg.pwCrypto )) assertIs<AccountCreationResult.Success>(db.account.create( - login = "customer", + username = "customer", password = "customer-password", name = "Customer", internalPayto = customerPayto, @@ -409,8 +409,8 @@ fun HttpRequestBuilder.pwAuth(username: String? = null) { basicAuth("admin", "admin-password") } else if (url.pathSegments[1] == "accounts") { // Extract username from path - val login = url.pathSegments[2] - basicAuth(login, "$login-password") + val username = url.pathSegments[2] + basicAuth(username, "$username-password") } } diff --git a/database-versioning/libeufin-bank-0008.sql b/database-versioning/libeufin-bank-0008.sql @@ -0,0 +1,29 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2024 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + +BEGIN; + +SELECT _v.register_patch('libeufin-bank-0008', NULL, NULL); +SET search_path TO libeufin_bank; + +ALTER TABLE customers RENAME COLUMN login TO username; +ALTER TABLE bank_accounts RENAME internal_payto_uri TO internal_payto; +ALTER TABLE bank_account_transactions RENAME debtor_payto_uri TO debtor_payto; +ALTER TABLE bank_account_transactions RENAME creditor_payto_uri TO creditor_payto; +ALTER TABLE bank_account_transactions + DROP COLUMN account_servicer_reference, + DROP COLUMN payment_information_id, + DROP COLUMN end_to_end_id; +COMMIT; diff --git a/database-versioning/libeufin-bank-procedures.sql b/database-versioning/libeufin-bank-procedures.sql @@ -236,7 +236,7 @@ SELECT has_debt, (balance).val, (balance).frac, (max_debt).val, (max_debt).frac, - internal_payto_uri, customers.name + internal_payto, customers.name INTO debtor_has_debt, debtor_balance.val, debtor_balance.frac, @@ -252,7 +252,7 @@ END IF; SELECT has_debt, (balance).val, (balance).frac, - internal_payto_uri, customers.name + internal_payto, customers.name INTO creditor_has_debt, creditor_balance.val, creditor_balance.frac, @@ -267,14 +267,14 @@ END IF; SELECT bank_account_id, has_debt, (balance).val, (balance).frac, - internal_payto_uri, customers.name + internal_payto, customers.name INTO admin_account_id, admin_has_debt, admin_balance.val, admin_balance.frac, admin_payto, admin_name FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = 'admin'; + WHERE username = 'admin'; IF NOT FOUND THEN RAISE EXCEPTION 'No admin'; END IF; @@ -392,9 +392,9 @@ END IF; -- now actually create the bank transaction. -- debtor side: INSERT INTO bank_account_transactions ( - creditor_payto_uri + creditor_payto ,creditor_name - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,subject ,amount @@ -416,9 +416,9 @@ VALUES ( -- debtor side: INSERT INTO bank_account_transactions ( - creditor_payto_uri + creditor_payto ,creditor_name - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,subject ,amount @@ -454,9 +454,9 @@ WHERE bank_account_id=in_creditor_account_id; -- Fee part IF amount_with_fee != in_amount THEN INSERT INTO bank_account_transactions ( - creditor_payto_uri + creditor_payto ,creditor_name - ,debtor_payto_uri + ,debtor_payto ,debtor_name ,subject ,amount @@ -498,7 +498,7 @@ PERFORM pg_notify('bank_tx', in_debtor_account_id || ' ' || in_creditor_account_ END $$; CREATE FUNCTION account_delete( - IN in_login TEXT, + IN in_username TEXT, IN in_timestamp INT8, IN in_is_tan BOOLEAN, OUT out_not_found BOOLEAN, @@ -520,7 +520,7 @@ SELECT ,out_balance_not_zero FROM customers JOIN bank_accounts ON owning_customer_id = customer_id - WHERE login = in_login AND deleted_at IS NULL; + WHERE username = in_username AND deleted_at IS NULL; IF NOT FOUND OR out_balance_not_zero OR out_tan_required THEN out_not_found=NOT FOUND; RETURN; @@ -639,7 +639,7 @@ credit_row_id INT8; BEGIN -- Check for idempotence and conflict SELECT (amount != in_amount - OR creditor_payto_uri != in_credit_account_payto + OR creditor_payto != in_credit_account_payto OR exchange_base_url != in_exchange_base_url OR wtid != in_wtid) ,bank_transaction_id, transaction_date @@ -658,7 +658,7 @@ SELECT FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = in_username AND deleted_at IS NULL; + WHERE username = in_username AND deleted_at IS NULL; IF NOT FOUND OR out_debtor_not_exchange THEN out_debtor_not_found=NOT FOUND; RETURN; @@ -668,7 +668,7 @@ SELECT bank_account_id, is_taler_exchange INTO receiver_bank_account_id, out_both_exchanges FROM bank_accounts - WHERE internal_payto_uri = in_credit_account_payto; + WHERE internal_payto = in_credit_account_payto; IF NOT FOUND OR out_both_exchanges THEN out_creditor_not_found=NOT FOUND; RETURN; @@ -738,7 +738,7 @@ SELECT FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = in_username AND deleted_at IS NULL; + WHERE username = in_username AND deleted_at IS NULL; IF NOT FOUND OR out_creditor_not_exchange THEN out_creditor_not_found=NOT FOUND; RETURN; @@ -748,7 +748,7 @@ SELECT bank_account_id, is_taler_exchange INTO sender_bank_account_id, out_both_exchanges FROM bank_accounts - WHERE internal_payto_uri = in_debit_account_payto; + WHERE internal_payto = in_debit_account_payto; IF NOT FOUND OR out_both_exchanges THEN out_debtor_not_found=NOT FOUND; RETURN; @@ -814,11 +814,11 @@ CREATE FUNCTION bank_transaction( LANGUAGE plpgsql AS $$ BEGIN -- Find credit bank account id and check it's not admin -SELECT bank_account_id, is_taler_exchange, login='admin' +SELECT bank_account_id, is_taler_exchange, username='admin' INTO out_credit_bank_account_id, out_creditor_is_exchange, out_creditor_admin FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE internal_payto_uri = in_credit_account_payto AND deleted_at IS NULL; + WHERE internal_payto = in_credit_account_payto AND deleted_at IS NULL; IF NOT FOUND OR out_creditor_admin THEN out_creditor_not_found=NOT FOUND; RETURN; @@ -828,7 +828,7 @@ SELECT bank_account_id, is_taler_exchange, out_credit_bank_account_id=bank_accou INTO out_debit_bank_account_id, out_debtor_is_exchange, out_same_account, out_tan_required FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = in_debit_account_username AND deleted_at IS NULL; + WHERE username = in_debit_account_username AND deleted_at IS NULL; IF NOT FOUND OR out_same_account THEN out_debtor_not_found=NOT FOUND; RETURN; @@ -908,7 +908,7 @@ SELECT bank_account_id, is_taler_exchange INTO account_id, out_account_is_exchange FROM bank_accounts JOIN customers ON bank_accounts.owning_customer_id = customers.customer_id - WHERE login=in_account_username AND deleted_at IS NULL; + WHERE username=in_account_username AND deleted_at IS NULL; IF NOT FOUND OR out_account_is_exchange THEN out_account_not_found=NOT FOUND; RETURN; @@ -997,7 +997,7 @@ IF not_selected THEN SELECT NOT is_taler_exchange INTO out_account_is_not_exchange FROM bank_accounts - WHERE internal_payto_uri=in_selected_exchange_payto; + WHERE internal_payto=in_selected_exchange_payto; IF NOT FOUND OR out_account_is_not_exchange THEN out_account_not_found=NOT FOUND; RETURN; @@ -1054,7 +1054,7 @@ END $$; COMMENT ON FUNCTION abort_taler_withdrawal IS 'Abort a withdrawal operation.'; CREATE FUNCTION confirm_taler_withdrawal( - IN in_login TEXT, + IN in_username TEXT, IN in_withdrawal_uuid uuid, IN in_timestamp INT8, IN in_is_tan BOOLEAN, @@ -1101,7 +1101,7 @@ SELECT FROM taler_withdrawal_operations JOIN bank_accounts ON wallet_bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id - WHERE withdrawal_uuid=in_withdrawal_uuid AND login=in_login AND deleted_at IS NULL; + WHERE withdrawal_uuid=in_withdrawal_uuid AND username=in_username AND deleted_at IS NULL; IF NOT FOUND OR already_confirmed OR out_aborted OR out_not_selected THEN out_no_op=NOT FOUND; RETURN; @@ -1112,7 +1112,7 @@ SELECT bank_account_id INTO exchange_bank_account_id FROM bank_accounts - WHERE internal_payto_uri = selected_exchange_payto_local; + WHERE internal_payto = selected_exchange_payto_local; IF NOT FOUND OR out_tan_required THEN out_exchange_not_found=NOT FOUND; RETURN; @@ -1177,7 +1177,7 @@ SELECT bank_account_id FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = 'exchange'; + WHERE username = 'exchange'; IF NOT FOUND THEN out_no_account = true; RETURN; @@ -1189,7 +1189,7 @@ SELECT bank_account_id FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = 'admin'; + WHERE username = 'admin'; -- Perform conversion SELECT (converted).val, (converted).frac, too_small, no_config @@ -1231,7 +1231,7 @@ COMMENT ON FUNCTION cashin IS 'Perform a cashin operation'; CREATE FUNCTION cashout_create( - IN in_login TEXT, + IN in_username TEXT, IN in_request_uid BYTEA, IN in_amount_debit taler_amount, IN in_amount_credit taler_amount, @@ -1269,7 +1269,7 @@ SELECT out_no_cashout_payto, out_tan_required FROM bank_accounts JOIN customers ON owning_customer_id=customer_id - WHERE login=in_login; + WHERE username=in_username; IF NOT FOUND THEN out_account_not_found=TRUE; RETURN; @@ -1294,7 +1294,7 @@ SELECT bank_account_id FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE login = 'admin'; + WHERE username = 'admin'; -- Check for idempotence and conflict SELECT (amount_debit != in_amount_debit @@ -1355,7 +1355,7 @@ CREATE FUNCTION tan_challenge_create ( IN in_timestamp INT8, IN in_validity_period INT8, IN in_retry_counter INT4, - IN in_login TEXT, + IN in_username TEXT, IN in_tan_channel tan_enum, IN in_tan_info TEXT, OUT out_challenge_id INT8 @@ -1365,7 +1365,7 @@ DECLARE account_id INT8; BEGIN -- Retrieve account id -SELECT customer_id INTO account_id FROM customers WHERE login = in_login AND deleted_at IS NULL; +SELECT customer_id INTO account_id FROM customers WHERE username = in_username AND deleted_at IS NULL; -- Create challenge INSERT INTO tan_challenges ( body, @@ -1393,7 +1393,7 @@ COMMENT ON FUNCTION tan_challenge_create IS 'Create a new challenge, return the CREATE FUNCTION tan_challenge_send ( IN in_challenge_id INT8, - IN in_login TEXT, + IN in_username TEXT, IN in_code TEXT, -- New code to use if the old code expired IN in_timestamp INT8, IN in_validity_period INT8, @@ -1417,7 +1417,7 @@ SELECT customer_id, tan_channel, CASE tan_channel WHEN 'email' THEN email END INTO account_id, out_tan_channel, out_tan_info -FROM customers WHERE login = in_login AND deleted_at IS NULL; +FROM customers WHERE username = in_username AND deleted_at IS NULL; -- Recover expiration date SELECT @@ -1458,7 +1458,7 @@ COMMENT ON FUNCTION tan_challenge_mark_sent IS 'Register a challenge as successf CREATE FUNCTION tan_challenge_try ( IN in_challenge_id INT8, - IN in_login TEXT, + IN in_username TEXT, IN in_code TEXT, IN in_timestamp INT8, -- Error status @@ -1477,7 +1477,7 @@ DECLARE account_id INT8; BEGIN -- Retrieve account id -SELECT customer_id INTO account_id FROM customers WHERE login = in_login AND deleted_at IS NULL; +SELECT customer_id INTO account_id FROM customers WHERE username = in_username AND deleted_at IS NULL; -- Check challenge UPDATE tan_challenges SET confirmation_date = CASE diff --git a/database-versioning/libeufin-conversion-setup.sql b/database-versioning/libeufin-conversion-setup.sql @@ -19,10 +19,10 @@ LANGUAGE plpgsql AS $$ WHERE bank_account_id=NEW.bank_account; INSERT INTO libeufin_nexus.initiated_outgoing_transactions ( amount - ,wire_transfer_subject - ,credit_payto_uri + ,subject + ,credit_payto ,initiation_time - ,request_uid + ,end_to_end_id ) VALUES ( ((NEW.amount_credit).val, (NEW.amount_credit).frac)::libeufin_nexus.taler_amount ,NEW.subject @@ -48,7 +48,7 @@ LANGUAGE plpgsql AS $$ DECLARE now_date INT8; local_amount libeufin_bank.taler_amount; - subject TEXT; + local_subject TEXT; too_small BOOLEAN; balance_insufficient BOOLEAN; no_account BOOLEAN; @@ -59,14 +59,14 @@ LANGUAGE plpgsql AS $$ RETURN NEW; END IF; - SELECT (amount).val, (amount).frac, wire_transfer_subject, execution_time - INTO local_amount.val, local_amount.frac, subject, now_date + SELECT (amount).val, (amount).frac, subject, execution_time + INTO local_amount.val, local_amount.frac, local_subject, now_date FROM libeufin_nexus.incoming_transactions WHERE incoming_transaction_id = NEW.incoming_transaction_id; SET search_path TO libeufin_bank; SELECT out_too_small, out_balance_insufficient, out_no_account, out_no_config INTO too_small, balance_insufficient, no_account, no_config - FROM libeufin_bank.cashin(now_date, NEW.reserve_public_key, local_amount, subject); + FROM libeufin_bank.cashin(now_date, NEW.reserve_public_key, local_amount, local_subject); SET search_path TO libeufin_nexus; -- Bounce on soft failures diff --git a/database-versioning/libeufin-nexus-0007.sql b/database-versioning/libeufin-nexus-0007.sql @@ -62,4 +62,15 @@ COMMENT ON INDEX initiated_outgoing_batches_status_index IS 'for listing taler b CREATE INDEX initiated_outgoing_transactions_batch_index ON initiated_outgoing_transactions (initiated_outgoing_batch_id); COMMENT ON INDEX initiated_outgoing_transactions_batch_index IS 'for listing transactions in batches'; +-- Renaming +ALTER TABLE incoming_transactions RENAME COLUMN wire_transfer_subject TO subject; +ALTER TABLE incoming_transactions RENAME COLUMN debit_payto_uri TO debit_payto; +ALTER TABLE outgoing_transactions RENAME COLUMN wire_transfer_subject TO subject; +ALTER TABLE outgoing_transactions RENAME COLUMN credit_payto_uri TO credit_payto; +ALTER TABLE outgoing_transactions RENAME COLUMN message_id TO end_to_end_id; +ALTER TABLE initiated_outgoing_transactions RENAME COLUMN wire_transfer_subject TO subject; +ALTER TABLE initiated_outgoing_transactions RENAME COLUMN credit_payto_uri TO credit_payto; +ALTER TABLE initiated_outgoing_transactions RENAME COLUMN submitted TO status; +ALTER TABLE initiated_outgoing_transactions RENAME COLUMN failure_message TO status_msg; +ALTER TABLE initiated_outgoing_transactions RENAME COLUMN request_uid TO end_to_end_id; COMMIT; diff --git a/database-versioning/libeufin-nexus-procedures.sql b/database-versioning/libeufin-nexus-procedures.sql @@ -59,9 +59,9 @@ COMMENT ON FUNCTION amount_add CREATE FUNCTION register_outgoing( IN in_amount taler_amount - ,IN in_wire_transfer_subject TEXT + ,IN in_subject TEXT ,IN in_execution_time INT8 - ,IN in_credit_payto_uri TEXT + ,IN in_credit_payto TEXT ,IN in_end_to_end_id TEXT ,IN in_wtid BYTEA ,IN in_exchange_url TEXT @@ -77,7 +77,7 @@ BEGIN -- Check if already registered SELECT outgoing_transaction_id INTO out_tx_id FROM outgoing_transactions - WHERE message_id = in_end_to_end_id; + WHERE end_to_end_id = in_end_to_end_id; IF FOUND THEN out_found = true; -- TODO Should we update the subject and credit payto if it's finally found @@ -89,15 +89,15 @@ ELSE -- Store the transaction in the database INSERT INTO outgoing_transactions ( amount - ,wire_transfer_subject + ,subject ,execution_time - ,credit_payto_uri - ,message_id + ,credit_payto + ,end_to_end_id ) VALUES ( in_amount - ,in_wire_transfer_subject + ,in_subject ,in_execution_time - ,in_credit_payto_uri + ,in_credit_payto ,in_end_to_end_id ) RETURNING outgoing_transaction_id @@ -107,9 +107,9 @@ ELSE UPDATE initiated_outgoing_transactions SET outgoing_transaction_id = out_tx_id - ,submitted = 'success' - ,failure_message = null - WHERE request_uid = in_end_to_end_id + ,status = 'success' + ,status_msg = null + WHERE end_to_end_id = in_end_to_end_id RETURNING true INTO out_initiated; -- Reconciles the related initiated batch @@ -136,9 +136,9 @@ COMMENT ON FUNCTION register_outgoing CREATE FUNCTION register_incoming( IN in_amount taler_amount - ,IN in_wire_transfer_subject TEXT + ,IN in_subject TEXT ,IN in_execution_time INT8 - ,IN in_debit_payto_uri TEXT + ,IN in_debit_payto TEXT ,IN in_bank_id TEXT ,OUT out_found BOOLEAN ,OUT out_tx_id INT8 @@ -156,15 +156,15 @@ ELSE -- Store the transaction in the database INSERT INTO incoming_transactions ( amount - ,wire_transfer_subject + ,subject ,execution_time - ,debit_payto_uri + ,debit_payto ,bank_id ) VALUES ( in_amount - ,in_wire_transfer_subject + ,in_subject ,in_execution_time - ,in_debit_payto_uri + ,in_debit_payto ,in_bank_id ) RETURNING incoming_transaction_id INTO out_tx_id; PERFORM pg_notify('revenue_tx', out_tx_id::text); @@ -186,7 +186,7 @@ payto_uri TEXT; init_id INT8; BEGIN -- Get incoming transaction bank ID and creditor -SELECT bank_id, debit_payto_uri +SELECT bank_id, debit_payto INTO local_bank_id, payto_uri FROM incoming_transactions WHERE incoming_transaction_id = tx_id; @@ -200,10 +200,10 @@ SELECT upper(substr(encode(public.digest(local_bank_id, 'sha256'), 'base64'), 0, -- Initiate the bounce transaction INSERT INTO initiated_outgoing_transactions ( amount - ,wire_transfer_subject - ,credit_payto_uri + ,subject + ,credit_payto ,initiation_time - ,request_uid + ,end_to_end_id ) VALUES ( in_bounce_amount ,'bounce: ' || local_bank_id @@ -211,7 +211,7 @@ INSERT INTO initiated_outgoing_transactions ( ,in_now_date ,out_bounce_id ) - ON CONFLICT (request_uid) DO NOTHING -- idempotent + ON CONFLICT (end_to_end_id) DO NOTHING -- idempotent RETURNING initiated_outgoing_transaction_id INTO init_id; IF FOUND THEN -- Register the bounce @@ -225,9 +225,9 @@ COMMENT ON FUNCTION bounce_incoming CREATE FUNCTION register_incoming_and_bounce( IN in_amount taler_amount - ,IN in_wire_transfer_subject TEXT + ,IN in_subject TEXT ,IN in_execution_time INT8 - ,IN in_debit_payto_uri TEXT + ,IN in_debit_payto TEXT ,IN in_bank_id TEXT ,IN in_bounce_amount taler_amount ,IN in_now_date INT8 @@ -241,7 +241,7 @@ init_id INT8; BEGIN -- Register the incoming transaction SELECT reg.out_found, reg.out_tx_id - FROM register_incoming(in_amount, in_wire_transfer_subject, in_execution_time, in_debit_payto_uri, in_bank_id) as reg + FROM register_incoming(in_amount, in_subject, in_execution_time, in_debit_payto, in_bank_id) as reg INTO out_found, out_tx_id; -- Bounce the incoming transaction @@ -252,9 +252,9 @@ COMMENT ON FUNCTION register_incoming_and_bounce CREATE FUNCTION register_incoming_and_talerable( IN in_amount taler_amount - ,IN in_wire_transfer_subject TEXT + ,IN in_subject TEXT ,IN in_execution_time INT8 - ,IN in_debit_payto_uri TEXT + ,IN in_debit_payto TEXT ,IN in_bank_id TEXT ,IN in_type taler_incoming_type ,IN in_reserve_pub BYTEA @@ -275,8 +275,8 @@ IF in_type = 'reserve' THEN -- Check for reserve_pub reuse SELECT incoming_transaction_id, bank_id IS DISTINCT FROM in_bank_id, bank_id IS NULL AND amount = in_amount - AND debit_payto_uri = in_debit_payto_uri - AND wire_transfer_subject = in_wire_transfer_subject + AND debit_payto = in_debit_payto + AND subject = in_subject INTO out_tx_id, out_reserve_pub_reuse, need_reconcile FROM talerable_incoming_transactions JOIN incoming_transactions USING(incoming_transaction_id) @@ -300,8 +300,8 @@ ELSIF in_type = 'kyc' THEN JOIN incoming_transactions USING(incoming_transaction_id) WHERE account_pub = in_account_pub AND amount = in_amount - AND debit_payto_uri = in_debit_payto_uri - AND wire_transfer_subject = in_wire_transfer_subject; + AND debit_payto = in_debit_payto + AND subject = in_subject; IF FOUND THEN -- If bank_id is missing we assume it's the same transaction @@ -320,7 +320,7 @@ END IF; -- Register the incoming transaction SELECT reg.out_found, reg.out_tx_id - FROM register_incoming(in_amount, in_wire_transfer_subject, in_execution_time, in_debit_payto_uri, in_bank_id) as reg + FROM register_incoming(in_amount, in_subject, in_execution_time, in_debit_payto, in_bank_id) as reg INTO out_found, out_tx_id; -- Register as talerable @@ -352,7 +352,7 @@ CREATE FUNCTION taler_transfer( IN in_amount taler_amount, IN in_exchange_base_url TEXT, IN in_credit_account_payto TEXT, - IN in_bank_id TEXT, + IN in_end_to_end_id TEXT, IN in_timestamp INT8, -- Error status OUT out_request_uid_reuse BOOLEAN, @@ -364,7 +364,7 @@ LANGUAGE plpgsql AS $$ BEGIN -- Check for idempotence and conflict SELECT (amount != in_amount - OR credit_payto_uri != in_credit_account_payto + OR credit_payto != in_credit_account_payto OR exchange_base_url != in_exchange_base_url OR wtid != in_wtid) ,transfer_operations.initiated_outgoing_transaction_id, initiation_time @@ -379,16 +379,16 @@ END IF; -- Initiate bank transfer INSERT INTO initiated_outgoing_transactions ( amount - ,wire_transfer_subject - ,credit_payto_uri + ,subject + ,credit_payto ,initiation_time - ,request_uid + ,end_to_end_id ) VALUES ( in_amount ,in_subject ,in_credit_account_payto ,in_timestamp - ,in_bank_id + ,in_end_to_end_id ) RETURNING initiated_outgoing_transaction_id INTO out_tx_row_id; -- Register outgoing transaction INSERT INTO transfer_operations( diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt @@ -32,6 +32,7 @@ import tech.libeufin.nexus.db.Database import tech.libeufin.nexus.db.ExchangeDAO import tech.libeufin.nexus.db.ExchangeDAO.TransferResult import tech.libeufin.nexus.db.PaymentDAO.IncomingRegistrationResult +import tech.libeufin.nexus.ebics.randEbicsId import tech.libeufin.nexus.iso20022.* import java.time.Instant @@ -46,13 +47,10 @@ fun Routing.wireGatewayApi(db: Database, cfg: NexusConfig) = authApi(cfg.wireGat val req = call.receive<TransferRequest>() cfg.checkCurrency(req.amount) req.credit_account.expectRequestIban() - val bankId = run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } + val endToEndId = randEbicsId() val res = db.exchange.transfer( req, - bankId, + endToEndId, Instant.now() ) when (res) { @@ -113,14 +111,11 @@ fun Routing.wireGatewayApi(db: Database, cfg: NexusConfig) = authApi(cfg.wireGat cfg.checkCurrency(amount) debitAccount.expectRequestIban() val timestamp = Instant.now() - val bankId = run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } + val bankId = randEbicsId() val res = db.payment.registerTalerableIncoming(IncomingPayment( amount = amount, debitPaytoUri = debitAccount.toString(), - wireTransferSubject = subject, + subject = subject, executionTime = timestamp, bankId = bankId ), metadata) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsFetch.kt @@ -43,7 +43,7 @@ suspend fun ingestOutgoingPayment( db: Database, payment: OutgoingPayment ) { - val metadata: Pair<ShortHashCode, ExchangeUrl>? = payment.wireTransferSubject?.let { + val metadata: Pair<ShortHashCode, ExchangeUrl>? = payment.subject?.let { runCatching { parseOutgoingTxMetadata(it) }.getOrNull() } val result = db.payment.registerOutgoing(payment, metadata?.first, metadata?.second) @@ -94,7 +94,7 @@ suspend fun ingestIncomingPayment( } } } - runCatching { parseIncomingTxMetadata(payment.wireTransferSubject) }.fold( + runCatching { parseIncomingTxMetadata(payment.subject) }.fold( onSuccess = { metadata -> when (val res = db.payment.registerTalerableIncoming(payment, metadata)) { IncomingRegistrationResult.ReservePubReuse -> bounce("reverse pub reuse") diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSubmit.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSubmit.kt @@ -56,7 +56,7 @@ private suspend fun submitBatch( name = payto.receiverName!! ), amount = payment.amount, - subject = payment.wireTransferSubject, + subject = payment.subject, endToEndId = payment.endToEndId ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/InitiatePayment.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/InitiatePayment.kt @@ -26,6 +26,7 @@ import com.github.ajalt.clikt.parameters.options.convert import com.github.ajalt.clikt.parameters.options.option import tech.libeufin.common.* import tech.libeufin.nexus.db.InitiatedPayment +import tech.libeufin.nexus.ebics.randEbicsId import tech.libeufin.nexus.logger import tech.libeufin.nexus.nexusConfig import tech.libeufin.nexus.withDb @@ -60,19 +61,14 @@ class InitiatePayment: CliktCommand("Initiate an outgoing payment") { "Wrong currency: expected ${cfg.currency} got ${amount.currency}" } - val endToEndId = endToEndId ?: run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } - db.initiated.create( InitiatedPayment( id = -1, amount = amount, - wireTransferSubject = subject, + subject = subject, creditPaytoUri = payto.toString(), initiationTime = Instant.now(), - endToEndId = endToEndId + endToEndId = endToEndId ?: randEbicsId() ) ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/Testing.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/Testing.kt @@ -85,19 +85,14 @@ class FakeIncoming: CliktCommand("Genere a fake incoming payment") { require(amount.currency == cfg.currency) { "Wrong currency: expected ${cfg.currency} got ${amount.currency}" } - - val bankId = run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } ingestIncomingPayment(db, IncomingPayment( amount = amount, debitPaytoUri = payto.toString(), - wireTransferSubject = subject, + subject = subject, executionTime = Instant.now(), - bankId = bankId + bankId = randEbicsId() ), cfg.accountType ) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/Database.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/Database.kt @@ -40,7 +40,7 @@ data class PaymentBatch( data class InitiatedPayment( val id: Long, val amount: TalerAmount, - val wireTransferSubject: String, + val subject: String, val creditPaytoUri: String, val initiationTime: Instant, val endToEndId: String diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt @@ -35,7 +35,7 @@ class ExchangeDAO(private val db: Database) { ,execution_time ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,debit_payto_uri + ,debit_payto ,type ,reserve_public_key ,account_pub @@ -49,14 +49,14 @@ class ExchangeDAO(private val db: Database) { row_id = it.getLong("incoming_transaction_id"), date = it.getTalerTimestamp("execution_time"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getString("debit_payto_uri"), + debit_account = it.getString("debit_payto"), reserve_pub = EddsaPublicKey(it.getBytes("reserve_public_key")), ) TalerIncomingType.kyc -> IncomingKycAuthTransaction( row_id = it.getLong("incoming_transaction_id"), date = it.getTalerTimestamp("execution_time"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getString("debit_payto_uri"), + debit_account = it.getString("debit_payto"), account_pub = EddsaPublicKey(it.getBytes("account_pub")), ) TalerIncomingType.wad -> throw UnsupportedOperationException() @@ -73,7 +73,7 @@ class ExchangeDAO(private val db: Database) { ,execution_time ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,credit_payto_uri + ,credit_payto ,wtid ,exchange_base_url FROM talerable_outgoing_transactions @@ -84,7 +84,7 @@ class ExchangeDAO(private val db: Database) { row_id = it.getLong("outgoing_transaction_id"), date = it.getTalerTimestamp("execution_time"), amount = it.getAmount("amount", db.bankCurrency), - credit_account = it.getString("credit_payto_uri"), + credit_account = it.getString("credit_payto"), wtid = ShortHashCode(it.getBytes("wtid")), exchange_base_url = it.getString("exchange_base_url") ) @@ -100,7 +100,7 @@ class ExchangeDAO(private val db: Database) { /** Perform a Taler transfer */ suspend fun transfer( req: TransferRequest, - bankId: String, + endToEndId: String, timestamp: Instant ): TransferResult = db.serializable( """ @@ -124,7 +124,7 @@ class ExchangeDAO(private val db: Database) { setInt(5, req.amount.frac) setString(6, req.exchange_base_url.url) setString(7, req.credit_account.canonical) - setString(8, bankId) + setString(8, endToEndId) setLong(9, timestamp.micros()) one { when { @@ -147,10 +147,10 @@ class ExchangeDAO(private val db: Database) { ,exchange_base_url ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,submitted - ,credit_payto_uri + ,credit_payto ,initiation_time - ,failure_message + ,status + ,status_msg FROM transfer_operations JOIN initiated_outgoing_transactions USING (initiated_outgoing_transaction_id) WHERE initiated_outgoing_transaction_id=? @@ -159,17 +159,17 @@ class ExchangeDAO(private val db: Database) { setLong(1, id) oneOrNull { TransferStatus( - status = when (it.getEnum<SubmissionState>("submitted")) { + status = when (it.getEnum<SubmissionState>("status")) { SubmissionState.unsubmitted, SubmissionState.pending -> TransferStatusState.pending SubmissionState.transient_failure -> TransferStatusState.transient_failure SubmissionState.permanent_failure -> TransferStatusState.permanent_failure SubmissionState.success -> TransferStatusState.success }, - status_msg = it.getString("failure_message"), + status_msg = it.getString("status_msg"), amount = it.getAmount("amount", db.bankCurrency), origin_exchange_url = it.getString("exchange_base_url"), wtid = ShortHashCode(it.getBytes("wtid")), - credit_account = it.getString("credit_payto_uri"), + credit_account = it.getString("credit_payto"), timestamp = it.getTalerTimestamp("initiation_time"), ) } @@ -186,16 +186,16 @@ class ExchangeDAO(private val db: Database) { initiated_outgoing_transaction_id ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,submitted - ,credit_payto_uri + ,status + ,credit_payto ,initiation_time FROM transfer_operations JOIN initiated_outgoing_transactions USING (initiated_outgoing_transaction_id) WHERE ${ when (params.status) { null -> "" - TransferStatusState.pending -> "(submitted=?::submission_state OR submitted=?::submission_state) AND" - else -> "submitted=?::submission_state AND" + TransferStatusState.pending -> "(status=?::submission_state OR status=?::submission_state) AND" + else -> "status=?::submission_state AND" } } """, @@ -216,14 +216,14 @@ class ExchangeDAO(private val db: Database) { ) { TransferListStatus( row_id = it.getLong("initiated_outgoing_transaction_id"), - status = when (it.getEnum<SubmissionState>("submitted")) { + status = when (it.getEnum<SubmissionState>("status")) { SubmissionState.unsubmitted, SubmissionState.pending -> TransferStatusState.pending SubmissionState.transient_failure -> TransferStatusState.transient_failure SubmissionState.permanent_failure -> TransferStatusState.permanent_failure SubmissionState.success -> TransferStatusState.success }, amount = it.getAmount("amount", db.bankCurrency), - credit_account = it.getString("credit_payto_uri"), + credit_account = it.getString("credit_payto"), timestamp = it.getTalerTimestamp("initiation_time"), ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/InitiatedDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/InitiatedDAO.kt @@ -38,10 +38,10 @@ class InitiatedDAO(private val db: Database) { """ INSERT INTO initiated_outgoing_transactions ( amount - ,wire_transfer_subject - ,credit_payto_uri + ,subject + ,credit_payto ,initiation_time - ,request_uid + ,end_to_end_id ) VALUES ((?,?)::taler_amount,?,?,?,?) RETURNING initiated_outgoing_transaction_id """ @@ -49,7 +49,7 @@ class InitiatedDAO(private val db: Database) { // TODO check payto uri setLong(1, paymentData.amount.value) setInt(2, paymentData.amount.frac) - setString(3, paymentData.wireTransferSubject) + setString(3, paymentData.subject) setString(4, paymentData.creditPaytoUri) setLong(5, paymentData.initiationTime.micros()) setString(6, paymentData.endToEndId) @@ -85,10 +85,10 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET submitted = 'pending'::submission_state - ,failure_message = NULL + SET status = 'pending'::submission_state + ,status_msg = NULL WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setLong(1, id) @@ -122,10 +122,10 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions SET - submitted = 'transient_failure'::submission_state - ,failure_message = ? + status = 'transient_failure'::submission_state + ,status_msg = ? WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setString(1, msg) @@ -154,9 +154,9 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET failure_message = ? + SET status_msg = ? WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setString(1, msg) @@ -191,9 +191,9 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET submitted = 'pending' + SET status = 'pending' WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setLong(1, batchId) @@ -228,9 +228,9 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET submitted = 'permanent_failure' + SET status = 'permanent_failure' WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setLong(1, batchId) @@ -267,10 +267,10 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET submitted = ?::submission_state, - failure_message = ? + SET status = ?::submission_state, + status_msg = ? WHERE initiated_outgoing_batch_id = ? - AND submitted NOT IN ('permanent_failure', 'success') + AND status NOT IN ('permanent_failure', 'success') """ ) { setString(1, txState.name) @@ -286,10 +286,10 @@ class InitiatedDAO(private val db: Database) { tx.withStatement( """ UPDATE initiated_outgoing_transactions - SET submitted = ?::submission_state, - failure_message = ? - WHERE request_uid = ? - AND submitted NOT IN ('permanent_failure', 'success') + SET status = ?::submission_state, + status_msg = ? + WHERE end_to_end_id = ? + AND status NOT IN ('permanent_failure', 'success') """ ) { setString(1, state.name) @@ -360,10 +360,10 @@ class InitiatedDAO(private val db: Database) { initiated_outgoing_transaction_id ,(amount).val as amount_val ,(amount).frac as amount_frac - ,wire_transfer_subject - ,credit_payto_uri + ,subject + ,credit_payto ,initiated_outgoing_transactions.initiation_time - ,request_uid + ,end_to_end_id ,initiated_outgoing_batch_id FROM initiated_outgoing_transactions JOIN initiated_outgoing_batches USING (initiated_outgoing_batch_id) @@ -374,10 +374,10 @@ class InitiatedDAO(private val db: Database) { val payment = InitiatedPayment( id = it.getLong("initiated_outgoing_transaction_id"), amount = it.getAmount("amount", currency), - creditPaytoUri = it.getString("credit_payto_uri"), - wireTransferSubject = it.getString("wire_transfer_subject"), + creditPaytoUri = it.getString("credit_payto"), + subject = it.getString("subject"), initiationTime = it.getLong("initiation_time").asInstant(), - endToEndId = it.getString("request_uid") + endToEndId = it.getString("end_to_end_id") ) val batchId = it.getLong("initiated_outgoing_batch_id") batches[batchId]!!.second.add(payment) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt @@ -50,7 +50,7 @@ class PaymentDAO(private val db: Database) { setLong(1, paymentData.amount.value) setInt(2, paymentData.amount.frac) - setString(3, paymentData.wireTransferSubject) + setString(3, paymentData.subject) setLong(4, executionTime) setString(5, paymentData.creditPaytoUri) setString(6, paymentData.endToEndId) @@ -87,7 +87,7 @@ class PaymentDAO(private val db: Database) { ) { setLong(1, paymentData.amount.value) setInt(2, paymentData.amount.frac) - setString(3, paymentData.wireTransferSubject) + setString(3, paymentData.subject) setLong(4, paymentData.executionTime.micros()) setString(5, paymentData.debitPaytoUri) setString(6, paymentData.bankId) @@ -122,7 +122,7 @@ class PaymentDAO(private val db: Database) { val executionTime = paymentData.executionTime.micros() setLong(1, paymentData.amount.value) setInt(2, paymentData.amount.frac) - setString(3, paymentData.wireTransferSubject) + setString(3, paymentData.subject) setLong(4, executionTime) setString(5, paymentData.debitPaytoUri) setString(6, paymentData.bankId) @@ -161,7 +161,7 @@ class PaymentDAO(private val db: Database) { val executionTime = paymentData.executionTime.micros() setLong(1, paymentData.amount.value) setInt(2, paymentData.amount.frac) - setString(3, paymentData.wireTransferSubject) + setString(3, paymentData.subject) setLong(4, executionTime) setString(5, paymentData.debitPaytoUri) setString(6, paymentData.bankId) @@ -183,16 +183,16 @@ class PaymentDAO(private val db: Database) { ,execution_time ,(amount).val AS amount_val ,(amount).frac AS amount_frac - ,debit_payto_uri - ,wire_transfer_subject + ,debit_payto + ,subject FROM incoming_transactions WHERE """, "incoming_transaction_id") { RevenueIncomingBankTransaction( row_id = it.getLong("incoming_transaction_id"), date = it.getTalerTimestamp("execution_time"), amount = it.getAmount("amount", db.bankCurrency), - debit_account = it.getString("debit_payto_uri"), - subject = it.getString("wire_transfer_subject") + debit_account = it.getString("debit_payto"), + subject = it.getString("subject") ) } @@ -202,9 +202,9 @@ class PaymentDAO(private val db: Database) { SELECT (amount).val as amount_val ,(amount).frac AS amount_frac - ,wire_transfer_subject + ,subject ,execution_time - ,debit_payto_uri + ,debit_payto ,bank_id ,type ,reserve_public_key @@ -219,8 +219,8 @@ class PaymentDAO(private val db: Database) { IncomingTxMetadata( date = it.getLong("execution_time").asInstant(), amount = it.getDecimal("amount"), - subject = it.getString("wire_transfer_subject"), - debtor = it.getString("debit_payto_uri"), + subject = it.getString("subject"), + debtor = it.getString("debit_payto"), id = it.getString("bank_id"), talerable = when (type) { null -> null @@ -238,10 +238,10 @@ class PaymentDAO(private val db: Database) { SELECT (amount).val as amount_val ,(amount).frac AS amount_frac - ,wire_transfer_subject + ,subject ,execution_time - ,credit_payto_uri - ,message_id + ,credit_payto + ,end_to_end_id ,wtid ,exchange_base_url FROM outgoing_transactions @@ -253,9 +253,9 @@ class PaymentDAO(private val db: Database) { OutgoingTxMetadata( date = it.getLong("execution_time").asInstant(), amount = it.getDecimal("amount"), - subject = it.getString("wire_transfer_subject"), - creditor = it.getString("credit_payto_uri"), - id = it.getString("message_id"), + subject = it.getString("subject"), + creditor = it.getString("credit_payto"), + id = it.getString("end_to_end_id"), wtid = it.getBytes("wtid")?.run { ShortHashCode(this) }, exchangeBaseUrl = it.getString("exchange_base_url") ) @@ -268,14 +268,14 @@ class PaymentDAO(private val db: Database) { SELECT (amount).val as amount_val ,(amount).frac AS amount_frac - ,wire_transfer_subject + ,subject ,initiation_time ,submission_date ,submission_counter - ,credit_payto_uri - ,submitted - ,request_uid - ,failure_message + ,credit_payto + ,end_to_end_id + ,initiated_outgoing_transactions.status + ,initiated_outgoing_transactions.status_msg FROM initiated_outgoing_transactions LEFT JOIN initiated_outgoing_batches USING (initiated_outgoing_batch_id) ORDER BY initiation_time @@ -285,11 +285,11 @@ class PaymentDAO(private val db: Database) { InitiatedTxMetadata( date = it.getLong("initiation_time").asInstant(), amount = it.getDecimal("amount"), - subject = it.getString("wire_transfer_subject"), - creditor = it.getString("credit_payto_uri"), - id = it.getString("request_uid"), - status = it.getString("submitted"), - msg = it.getString("failure_message"), + subject = it.getString("subject"), + creditor = it.getString("credit_payto"), + id = it.getString("end_to_end_id"), + status = it.getString("status"), + msg = it.getString("status_msg"), submissionTime = it.getLong("submission_date").asInstant(), submissionCounter = it.getInt("submission_counter") ) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt @@ -34,12 +34,12 @@ data class IncomingPayment( /** ISO20022 UETR or TxID */ val bankId: String? = null, // Null when TxID is wrong with Atruvia's implementation of instant transactions val amount: TalerAmount, - val wireTransferSubject: String, + val subject: String, override val executionTime: Instant, val debitPaytoUri: String ): TxNotification { override fun toString(): String { - return "IN ${executionTime.fmtDate()} $amount $bankId debitor=$debitPaytoUri subject=\"$wireTransferSubject\"" + return "IN ${executionTime.fmtDate()} $amount $bankId debitor=$debitPaytoUri subject=\"$subject\"" } } @@ -50,13 +50,13 @@ data class OutgoingPayment( /** ISO20022 MessageId */ val msgId: String? = null, val amount: TalerAmount, - val wireTransferSubject: String? = null, // Some implementation does not provide this for recovery + val subject: String? = null, // Some implementation does not provide this for recovery override val executionTime: Instant, val creditPaytoUri: String? = null // Some implementation does not provide this for recovery ): TxNotification { override fun toString(): String { val msgIdFmt = if (msgId == null) "" else "$msgId." - return "OUT ${executionTime.fmtDate()} $amount $msgIdFmt$endToEndId creditor=$creditPaytoUri subject=\"$wireTransferSubject\"" + return "OUT ${executionTime.fmtDate()} $amount $msgIdFmt$endToEndId creditor=$creditPaytoUri subject=\"$subject\"" } } @@ -498,7 +498,7 @@ private fun parseTxLogic(info: TxInfo): TxNotification { bankId = info.bankId, debitPaytoUri = info.debtorPayto, executionTime = info.bookDate, - wireTransferSubject = info.subject + subject = info.subject ) } is TxInfo.Debit -> { @@ -511,7 +511,7 @@ private fun parseTxLogic(info: TxInfo): TxNotification { msgId = info.id.msgId, executionTime = info.bookDate, creditPaytoUri = info.creditorPayto, - wireTransferSubject = info.subject + subject = info.subject ) } else { OutgoingBatch( diff --git a/nexus/src/test/kotlin/DatabaseTest.kt b/nexus/src/test/kotlin/DatabaseTest.kt @@ -176,7 +176,7 @@ class IncomingPaymentsTest { // Different medata with missing id is ignored ingestIncomingPayment(db, incomingMissingId.copy(amount = TalerAmount("KUDOS:9")), AccountType.exchange) - ingestIncomingPayment(db, incomingMissingId.copy(wireTransferSubject = "another $subject"), AccountType.exchange) + ingestIncomingPayment(db, incomingMissingId.copy(subject = "another $subject"), AccountType.exchange) db.checkCount(3, 2, 1) // Recover bank ID when metadata match @@ -219,7 +219,7 @@ class IncomingPaymentsTest { // Different medata with missing id are accepted ingestIncomingPayment(db, incomingMissingId.copy(amount = TalerAmount("KUDOS:9.5")), AccountType.exchange) - ingestIncomingPayment(db, incomingMissingId.copy(wireTransferSubject = "again another $subject"), AccountType.exchange) + ingestIncomingPayment(db, incomingMissingId.copy(subject = "again another $subject"), AccountType.exchange) db.checkCount(5, 0, 5) // Recover bank ID when metadata match @@ -247,7 +247,7 @@ class PaymentInitiationsTest { suspend fun checkBatchStatus(id: Int, status: SubmissionState, txStatus: SubmissionState? = null) { db.serializable( """ - SELECT bool_and(status=?::submission_state AND submitted=?::submission_state) + SELECT bool_and(initiated_outgoing_batches.status=?::submission_state AND initiated_outgoing_transactions.status=?::submission_state) FROM initiated_outgoing_batches JOIN initiated_outgoing_transactions USING (initiated_outgoing_batch_id) WHERE initiated_outgoing_batch_id=? diff --git a/nexus/src/test/kotlin/IngestionTest.kt b/nexus/src/test/kotlin/IngestionTest.kt @@ -79,7 +79,7 @@ class IngestionTest { // Check transactions status val batch_tx = this.serializable( """ - SELECT message_id, request_uid, submitted + SELECT message_id, end_to_end_id, initiated_outgoing_transactions.status FROM initiated_outgoing_transactions JOIN initiated_outgoing_batches USING (initiated_outgoing_batch_id) ORDER BY initiated_outgoing_batch_id, initiated_outgoing_transaction_id @@ -88,8 +88,8 @@ class IngestionTest { all { Triple( it.getString("message_id"), - it.getString("request_uid"), - it.getEnum<SubmissionState>("submitted") + it.getString("end_to_end_id"), + it.getEnum<SubmissionState>("status") ) }.groupBy( keySelector = { it.first }, @@ -104,9 +104,9 @@ class IngestionTest { SELECT bank_id ,(amount).val as amount_val ,(amount).frac AS amount_frac - ,wire_transfer_subject + ,subject ,execution_time - ,debit_payto_uri + ,debit_payto FROM incoming_transactions ORDER BY incoming_transaction_id """ @@ -115,9 +115,9 @@ class IngestionTest { IncomingPayment( bankId = it.getString("bank_id"), amount = it.getAmount("amount", this@check.bankCurrency), - wireTransferSubject = it.getString("wire_transfer_subject"), + subject = it.getString("subject"), executionTime = it.getLong("execution_time").asInstant(), - debitPaytoUri = it.getString("debit_payto_uri"), + debitPaytoUri = it.getString("debit_payto"), ) } } @@ -126,23 +126,23 @@ class IngestionTest { // Check outgoing transactions val outgoing_tx = this.serializable( """ - SELECT message_id + SELECT end_to_end_id ,(amount).val as amount_val ,(amount).frac AS amount_frac - ,wire_transfer_subject + ,subject ,execution_time - ,credit_payto_uri + ,credit_payto FROM outgoing_transactions ORDER BY outgoing_transaction_id """ ) { all { OutgoingPayment( - endToEndId = it.getString("message_id"), + endToEndId = it.getString("end_to_end_id"), amount = it.getAmount("amount", this@check.bankCurrency), - wireTransferSubject = it.getString("wire_transfer_subject"), + subject = it.getString("subject"), executionTime = it.getLong("execution_time").asInstant(), - creditPaytoUri = it.getString("credit_payto_uri"), + creditPaytoUri = it.getString("credit_payto"), ) } } @@ -289,7 +289,7 @@ class IngestionTest { IncomingPayment( bankId = "BYLADEM1WOR-G2910276709458A2", amount = TalerAmount("EUR:3"), - wireTransferSubject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", + subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", executionTime = dateToInstant("2024-04-12"), debitPaytoUri = "payto://iban/DE84500105177118117964?receiver-name=John%20Smith" ), @@ -298,21 +298,21 @@ class IngestionTest { OutgoingPayment( endToEndId = "COMPAT_SUCCESS", amount = TalerAmount("EUR:2"), - wireTransferSubject = "TestABC123", + subject = "TestABC123", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), OutgoingPayment( endToEndId = "FD622SMXKT5QWSAHDY0H8NYG3G", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "single 2024-09-02T14:29:52.875253314Z", + subject = "single 2024-09-02T14:29:52.875253314Z", executionTime = dateToInstant("2024-09-02"), creditPaytoUri = "payto://iban/DE89500105173198527518?receiver-name=Grothoff%20Hans" ), OutgoingPayment( endToEndId = "YF5QBARGQ0MNY0VK59S477VDG4", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "Simple tx", + subject = "Simple tx", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), diff --git a/nexus/src/test/kotlin/Iso20022Test.kt b/nexus/src/test/kotlin/Iso20022Test.kt @@ -99,21 +99,21 @@ class Iso20022Test { endToEndId = "ZS1PGNTSV0ZNDFAJBBWWB8015G", msgId = "ZS1PGNTSV0ZNDFAJBBWWB8015G", amount = TalerAmount("CHF:3.00"), - wireTransferSubject = null, + subject = null, executionTime = dateToInstant("2024-01-15"), creditPaytoUri = null ), IncomingPayment( bankId = "62e2b511-7313-4ccd-8d40-c9d8e612cd71", amount = TalerAmount("CHF:10"), - wireTransferSubject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YBG", + subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YBG", executionTime = dateToInstant("2023-12-19"), debitPaytoUri = "payto://iban/CH7389144832588726658?receiver-name=Mr%20Test" ), IncomingPayment( bankId = "62e2b511-7313-4ccd-8d40-c9d8e612cd71", amount = TalerAmount("CHF:2.53"), - wireTransferSubject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YB", + subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YB", executionTime = dateToInstant("2023-12-19"), debitPaytoUri = "payto://iban/CH7389144832588726658?receiver-name=Mr%20Test" ), @@ -155,7 +155,7 @@ class Iso20022Test { endToEndId = "COMPAT_SUCCESS", msgId = "COMPAT_SUCCESS", amount = TalerAmount("EUR:2"), - wireTransferSubject = "TestABC123", + subject = "TestABC123", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), @@ -167,7 +167,7 @@ class Iso20022Test { IncomingPayment( bankId = "BYLADEM1WOR-G2910276709458A2", amount = TalerAmount("EUR:3"), - wireTransferSubject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", + subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", executionTime = dateToInstant("2024-04-12"), debitPaytoUri = "payto://iban/DE84500105177118117964?receiver-name=John%20Smith" ), @@ -180,7 +180,7 @@ class Iso20022Test { endToEndId = "FD622SMXKT5QWSAHDY0H8NYG3G", msgId = "BATCH_SINGLE_SUCCESS", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "single 2024-09-02T14:29:52.875253314Z", + subject = "single 2024-09-02T14:29:52.875253314Z", executionTime = dateToInstant("2024-09-02"), creditPaytoUri = "payto://iban/DE89500105173198527518?receiver-name=Grothoff%20Hans" ), @@ -188,7 +188,7 @@ class Iso20022Test { endToEndId = "YF5QBARGQ0MNY0VK59S477VDG4", msgId = "YF5QBARGQ0MNY0VK59S477VDG4", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "Simple tx", + subject = "Simple tx", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), @@ -205,7 +205,7 @@ class Iso20022Test { endToEndId = "COMPAT_SUCCESS", msgId = "COMPAT_SUCCESS", amount = TalerAmount("EUR:2"), - wireTransferSubject = "TestABC123", + subject = "TestABC123", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), @@ -221,7 +221,7 @@ class Iso20022Test { IncomingPayment( bankId = "BYLADEM1WOR-G2910276709458A2", amount = TalerAmount("EUR:3"), - wireTransferSubject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", + subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-", executionTime = dateToInstant("2024-04-12"), debitPaytoUri = "payto://iban/DE84500105177118117964?receiver-name=John%20Smith" ), @@ -234,7 +234,7 @@ class Iso20022Test { endToEndId = "FD622SMXKT5QWSAHDY0H8NYG3G", msgId = "BATCH_SINGLE_SUCCESS", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "single 2024-09-02T14:29:52.875253314Z", + subject = "single 2024-09-02T14:29:52.875253314Z", executionTime = dateToInstant("2024-09-02"), creditPaytoUri = "payto://iban/DE89500105173198527518?receiver-name=Grothoff%20Hans" ), @@ -242,7 +242,7 @@ class Iso20022Test { endToEndId = "YF5QBARGQ0MNY0VK59S477VDG4", msgId = "YF5QBARGQ0MNY0VK59S477VDG4", amount = TalerAmount("EUR:1.1"), - wireTransferSubject = "Simple tx", + subject = "Simple tx", executionTime = dateToInstant("2024-04-18"), creditPaytoUri = "payto://iban/DE20500105172419259181?receiver-name=John%20Smith" ), @@ -258,7 +258,7 @@ class Iso20022Test { IncomingPayment( bankId = null, //"IS11PGENODEFF2DA8899900378806", amount = TalerAmount("EUR:2.5"), - wireTransferSubject = "Test ICT", + subject = "Test ICT", executionTime = dateToInstant("2024-05-05"), debitPaytoUri = "payto://iban/DE84500105177118117964?receiver-name=Mr%20Test" ) diff --git a/nexus/src/test/kotlin/bench.kt b/nexus/src/test/kotlin/bench.kt @@ -34,17 +34,17 @@ class Bench { val token64 = ByteArray(64) conn.genData(amount, sequenceOf( - "incoming_transactions(amount, wire_transfer_subject, execution_time, debit_payto_uri, bank_id)" to { + "incoming_transactions(amount, subject, execution_time, debit_payto, bank_id)" to { "(42,0)\tsubject\t0\tdebit_payto\tBANK_ID${it*2}\n" + "(42,0)\tsubject\t0\tdebit_payto\tBANK_ID${it*2+1}\n" + "(42,0)\tsubject\t0\tdebit_payto\t\\N\n" }, - "outgoing_transactions(amount, wire_transfer_subject, execution_time, credit_payto_uri, message_id)" to { - "(42,0)\tsubject\t0\tcredit_payto\tMSG_ID${it*2}\n" + - "(42,0)\tsubject\t0\tcredit_payto\tMSG_ID${it*2+1}\n" + "outgoing_transactions(amount, subject, execution_time, credit_payto, end_to_end_id)" to { + "(42,0)\tsubject\t0\tcredit_payto\tE2E_ID${it*2}\n" + + "(42,0)\tsubject\t0\tcredit_payto\tE2E_ID${it*2+1}\n" }, - "initiated_outgoing_transactions(amount, wire_transfer_subject, initiation_time, credit_payto_uri, outgoing_transaction_id, request_uid)" to { - "(42,0)\tsubject\t0\tcredit_payto\t${it*2}\tREQUEST_UID$it\n" + "initiated_outgoing_transactions(amount, subject, initiation_time, credit_payto, outgoing_transaction_id, end_to_end_id)" to { + "(42,0)\tsubject\t0\tcredit_payto\t${it*2}\tE2E_ID$it\n" }, "talerable_incoming_transactions(type, reserve_public_key, account_pub, incoming_transaction_id)" to { val hex = token32.rand().encodeHex() diff --git a/nexus/src/test/kotlin/helpers.kt b/nexus/src/test/kotlin/helpers.kt @@ -32,6 +32,7 @@ import tech.libeufin.nexus.cli.ingestIncomingPayment import tech.libeufin.nexus.cli.ingestOutgoingPayment import tech.libeufin.nexus.db.Database import tech.libeufin.nexus.db.InitiatedPayment +import tech.libeufin.nexus.ebics.randEbicsId import tech.libeufin.nexus.iso20022.* import java.time.Instant import kotlin.io.path.Path @@ -90,21 +91,18 @@ fun genInitPay( id = -1, amount = TalerAmount(amount), creditPaytoUri = creditPaytoUri, - wireTransferSubject = subject, + subject = subject, initiationTime = Instant.now(), endToEndId = endToEndId ) /** Generates an incoming payment, given its subject */ fun genInPay(subject: String, amount: String = "KUDOS:44"): IncomingPayment { - val bankId = run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } + val bankId = randEbicsId() return IncomingPayment( amount = TalerAmount(amount), debitPaytoUri = "payto://iban/not-used", - wireTransferSubject = subject, + subject = subject, executionTime = Instant.now(), bankId = bankId ) @@ -112,14 +110,11 @@ fun genInPay(subject: String, amount: String = "KUDOS:44"): IncomingPayment { /** Generates an outgoing payment, given its subject and end-to-end ID */ fun genOutPay(subject: String, endToEndId: String? = null): OutgoingPayment { - val id = endToEndId ?: run { - val bytes = ByteArray(16).rand() - Base32Crockford.encode(bytes) - } + val id = endToEndId ?: randEbicsId() return OutgoingPayment( amount = TalerAmount(44, 0, "KUDOS"), creditPaytoUri = "payto://iban/CH4189144589712575493?receiver-name=Test", - wireTransferSubject = subject, + subject = subject, executionTime = Instant.now(), endToEndId = id ) diff --git a/testbench/src/test/kotlin/IntegrationTest.kt b/testbench/src/test/kotlin/IntegrationTest.kt @@ -163,7 +163,7 @@ class IntegrationTest { val reservePayment = IncomingPayment( amount = TalerAmount("EUR:10"), debitPaytoUri = userPayTo.toString(), - wireTransferSubject = "Error test $reservePub", + subject = "Error test $reservePub", executionTime = Instant.now(), bankId = "reserve_error" ) @@ -177,7 +177,7 @@ class IntegrationTest { db, reservePayment.copy( bankId = "kyc", - wireTransferSubject = "Error test KYC:${EddsaPublicKey.rand()}" + subject = "Error test KYC:${EddsaPublicKey.rand()}" ), AccountType.exchange ) @@ -230,7 +230,7 @@ class IntegrationTest { // Check success val validPayment = reservePayment.copy( - wireTransferSubject = "Success $reservePub", + subject = "Success $reservePub", bankId = "success" ) ingestIncomingPayment(db, validPayment, AccountType.exchange) @@ -242,7 +242,7 @@ class IntegrationTest { // Check idempotency ingestIncomingPayment(db, validPayment, AccountType.exchange) ingestIncomingPayment(db, validPayment.copy( - wireTransferSubject="Success 2 $reservePub" + subject="Success 2 $reservePub" ), AccountType.exchange) db.checkCount(3, 1, 2) } diff --git a/testbench/src/test/kotlin/MigrationTest.kt b/testbench/src/test/kotlin/MigrationTest.kt @@ -71,6 +71,9 @@ class MigrationTest { // libeufin-bank-0007 conn.execSQLUpdate(Path("../database-versioning/libeufin-bank-0007.sql").readText()) + // libeufin-bank-0008 + conn.execSQLUpdate(Path("../database-versioning/libeufin-bank-0008.sql").readText()) + // libeufin-nexus-0001 conn.execSQLUpdate(Path("../database-versioning/libeufin-nexus-0001.sql").readText()) conn.execSQLUpdate("""