libeufin

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

commit 01cec79392cf07f7ab066885337318c1bdee2b17
parent c7e8b73d9bc438c3aac270084e5f259323306064
Author: ms <ms@taler.net>
Date:   Sun, 19 Sep 2021 09:23:34 +0200

Sanity-check usernames at Sandbox.

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt | 2+-
Mnexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt | 2+-
Mnexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt | 18+-----------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 11++++++++++-
Mutil/src/main/kotlin/HTTP.kt | 6+++---
Mutil/src/main/kotlin/strings.kt | 35+++++++++++++++++++++++++++++++++++
6 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt @@ -478,7 +478,7 @@ private fun getCurrency(facadeName: String): String { } } -fun talerFacadeRoutes(route: Route, httpClient: HttpClient) { +fun talerFacadeRoutes(route: Route) { route.get("/config") { val facadeId = ensureNonNull(call.parameters["fcid"]) call.request.requirePermission( diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt @@ -314,7 +314,7 @@ fun Route.ebicsBankConnectionRoutes(client: HttpClient) { } post("/download/{msgtype}") { - val orderType = requireNotNull(call.parameters["msgtype"]).toUpperCase(Locale.ROOT) + val orderType = requireNotNull(call.parameters["msgtype"]).uppercase(Locale.ROOT) if (orderType.length != 3) { throw NexusError(HttpStatusCode.BadRequest, "ebics order type must be three characters") } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt @@ -119,22 +119,6 @@ fun ApplicationCall.expectUrlParameter(name: String): String { ?: throw NexusError(HttpStatusCode.BadRequest, "Parameter '$name' not provided in URI") } -fun isValidResourceName(name: String): Boolean { - return name.matches(Regex("[a-z]([-a-z0-9]*[a-z0-9])?")) -} - -fun requireValidResourceName(name: String): String { - if (!isValidResourceName(name)) { - throw NexusError( - HttpStatusCode.BadRequest, - "Invalid resource name. The first character must be a lowercase letter, " + - "and all following characters (except for the last character) must be a dash, " + - "lowercase letter, or digit. The last character must be a lowercase letter or digit." - ) - } - return name -} - suspend inline fun <reified T : Any> ApplicationCall.receiveJson(): T { try { return this.receive() @@ -1060,7 +1044,7 @@ fun serverMain(host: String, port: Int) { } } route("/facades/{fcid}/taler-wire-gateway") { - talerFacadeRoutes(this, client) + talerFacadeRoutes(this) } route("/facades/{fcid}/anastasis") { anastasisFacadeRoutes(this, client) diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -99,9 +99,18 @@ class Superuser : CliktCommand("Add superuser or change pw") { execThrowableOrTerminate { dbCreateTables(getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME)) } + try { + requireValidResourceName(username) + } catch (e: UtilError) { + println(e) // Gives instructions about the allowed format. + exitProcess(1) + } transaction { + val user = SandboxUserEntity.find { + SandboxUsersTable.username eq username + }.firstOrNull() + val hashedPw = CryptoUtil.hashpw(password) - val user = SandboxUserEntity.find { SandboxUsersTable.username eq username }.firstOrNull() if (user == null) { SandboxUserEntity.new { this.username = this@Superuser.username diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt @@ -32,9 +32,9 @@ fun extractUserAndPassword(authorizationHeader: String): Pair<String, String> { // FIXME/note: line below doesn't check for "Basic" presence. val split = authorizationHeader.split(" ") val plainUserAndPass = String(base64ToBytes(split[1]), Charsets.UTF_8) - val ret = plainUserAndPass.split(":") - if (ret.size != 2) throw java.lang.Exception( - "HTTP Basic auth line does not contain username and (only) password" + val ret = plainUserAndPass.split(":", limit = 2) + if (ret.size < 2) throw java.lang.Exception( + "HTTP Basic auth line does not contain username and password" ) ret } catch (e: Exception) { diff --git a/util/src/main/kotlin/strings.kt b/util/src/main/kotlin/strings.kt @@ -148,4 +148,39 @@ private val ibanRegex = Regex("^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{1,30}$") fun validateIban(iban: String): Boolean { return ibanRegex.matches(iban) +} + +fun isValidResourceName(name: String): Boolean { + return name.matches(Regex("[a-z]([-a-z0-9]*[a-z0-9])?")) +} + +fun requireValidResourceName(name: String): String { + if (!isValidResourceName(name)) { + throw UtilError( + HttpStatusCode.BadRequest, + "Invalid resource name. The first character must be a lowercase letter, " + + "and all following characters (except for the last character) must be a dash, " + + "lowercase letter, or digit. The last character must be a lowercase letter or digit.", + LibeufinErrorCode.LIBEUFIN_EC_GENERIC_PARAMETER_MALFORMED + ) + } + return name +} + + +fun sanityCheckOrThrow(credentials: Pair<String, String>) { + if (!sanityCheckCredentials(credentials)) throw UtilError( + HttpStatusCode.BadRequest, + "Please only use alphanumeric credentials.", + LibeufinErrorCode.LIBEUFIN_EC_GENERIC_PARAMETER_MALFORMED + ) +} +/** + * Sanity-check user's credentials. + */ +fun sanityCheckCredentials(credentials: Pair<String, String>): Boolean { + val allowedChars = Regex("^[a-zA-Z0-9]+$") + if (!allowedChars.matches(credentials.first)) return false + if (!allowedChars.matches(credentials.second)) return false + return true } \ No newline at end of file