diff --git a/src/main/kotlin/com/oliver/kidio/backend/plugins/Routing.kt b/src/main/kotlin/com/oliver/kidio/backend/plugins/Routing.kt index 0654cc5..8d55bc8 100644 --- a/src/main/kotlin/com/oliver/kidio/backend/plugins/Routing.kt +++ b/src/main/kotlin/com/oliver/kidio/backend/plugins/Routing.kt @@ -13,6 +13,25 @@ import io.ktor.server.routing.* import org.mindrot.jbcrypt.BCrypt import java.util.UUID +fun isValidPassword(password: String): Boolean { + if (password.length < 8) return false + + val hasUppercase = password.any { it.isUpperCase() } + val hasEmoji = password.any { char -> + val type = Character.getType(char).toByte() + type == Character.SURROGATE || + type == Character.OTHER_SYMBOL || + char.code in 0x1F600..0x1F64F || + char.code in 0x1F300..0x1F5FF || + char.code in 0x1F680..0x1F6FF || + char.code in 0x2600..0x26FF + } + + val hasSpecialChar = password.any { !it.isLetterOrDigit() && !hasEmoji } + + return hasUppercase && hasSpecialChar && !hasEmoji +} + fun Application.configureRouting(repository: KidioRepository, jwtService : JwtService) { routing { post("/api/v1/auth/register") { @@ -21,10 +40,17 @@ fun Application.configureRouting(repository: KidioRepository, jwtService : JwtSe call.respond(HttpStatusCode.BadRequest, "Bitte füllen Sie alle Felder aus") return@post } + if (!isValidPassword(registerRequest.passwordPlain)) { + call.respond( + HttpStatusCode.BadRequest, + "Das Passwort muss mindestens 8 Zeichen lang sein, mindestens einen Großbuchstaben und ein Sonderzeichen enthalten und darf keine Emojis enthalten." + ) + return@post + } if (registerRequest.parentPin.length != 4) { call.respond(HttpStatusCode.BadRequest, "Die Eltern-PIN muss genau 4 Ziffern lang sein") return@post - } + } val existingUser = repository.findByEmail(registerRequest.email) if (existingUser != null) { call.respond(HttpStatusCode.Conflict, "Ein Benutzer mit dieser E-Mail-Adresse existiert bereits") diff --git a/src/test/kotlin/ServerTest.kt b/src/test/kotlin/ServerTest.kt index 0acddd7..e71914c 100644 --- a/src/test/kotlin/ServerTest.kt +++ b/src/test/kotlin/ServerTest.kt @@ -71,7 +71,7 @@ class ServerTest { setBody( """{ "email": "test@family.de", - "passwordPlain": "strengGeheim1", + "passwordPlain": "StrengGeheim1!", "familyName": "Familie Schmidt", "childAge": 8, "parentPin": "4321" @@ -87,7 +87,7 @@ class ServerTest { setBody( """{ "email": "test@family.de", - "passwordPlain": "strengGeheim1" + "passwordPlain": "StrengGeheim1!" }""" ) } @@ -97,6 +97,47 @@ class ServerTest { assertEquals("Familie Schmidt", loginJson.familyName) } + @Test + fun `test registration rejects invalid passwords`() = testApplication { + val jwtService = JwtService() + val repository = InMemoryKidioRepository() + + application { + install(ServerContentNegotiation) { + json() + } + configureSecurity(jwtService) + configureRouting(repository, jwtService) + } + + val invalidPasswords = listOf( + "Kurz1!", + "keingrossbuch1!", + "KeinSonder12", + "Passwort123!😊" + ) + + for (password in invalidPasswords) { + val response = client.post("/api/v1/auth/register") { + header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setBody( + """{ + "email": "test_${System.currentTimeMillis()}@family.de", + "passwordPlain": "$password", + "familyName": "Familie Schmidt", + "childAge": 8, + "parentPin": "4321" + }""" + ) + } + assertEquals( + HttpStatusCode.BadRequest, + response.status, + "Passwort '$password' hätte abgelehnt werden müssen!" + ) + } + } + @Test fun `test tasks endpoint and verify with jwt`() = testApplication { val jwtService = JwtService()