From 6aa3ddb28d9c500448190a01e1c77805de64a29f Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 8 Apr 2021 01:55:10 +0200 Subject: [PATCH] Add Password validation --- .../dcproject/common/validation/Password.kt | 22 +++++++++ src/test/kotlin/unit/Password Validation.kt | 45 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/kotlin/fr/dcproject/common/validation/Password.kt create mode 100644 src/test/kotlin/unit/Password Validation.kt diff --git a/src/main/kotlin/fr/dcproject/common/validation/Password.kt b/src/main/kotlin/fr/dcproject/common/validation/Password.kt new file mode 100644 index 0000000..3e6b0cb --- /dev/null +++ b/src/main/kotlin/fr/dcproject/common/validation/Password.kt @@ -0,0 +1,22 @@ +package fr.dcproject.common.validation + +import io.konform.validation.ValidationBuilder + +fun ValidationBuilder.passwordScore(minScore: Int) = + addConstraint("is not enough strong. Use Upper case, Lower case and special characters or juste use more characters.") { value -> + value.passwordScore() >= minScore + } + +fun String.passwordScore(): Int { + var score: Int = length + val alphaNum = ('a'..'z').toList() + ('A'..'Z').toList() + ('0'..'9').toList() + val specialCount = (length - toList().intersect(alphaNum).size) + score += specialCount.let { if (it > 3) 3 else it } + + val hasAlphaLower = toList().intersect(('a'..'z').toList()).size.let { if (it > 2) 2 else it } + val hasAlphaUpper = toList().intersect(('A'..'Z').toList()).size.let { if (it > 2) 2 else it } + val hasNum = toList().intersect(('0'..'9').toList()).size.let { if (it > 2) 2 else it } + score += (hasAlphaLower + hasAlphaUpper + hasNum - 2) * 2 + + return score +} \ No newline at end of file diff --git a/src/test/kotlin/unit/Password Validation.kt b/src/test/kotlin/unit/Password Validation.kt new file mode 100644 index 0000000..e39e500 --- /dev/null +++ b/src/test/kotlin/unit/Password Validation.kt @@ -0,0 +1,45 @@ +package unit + +import fr.dcproject.common.validation.passwordScore +import io.konform.validation.Invalid +import io.konform.validation.Valid +import io.konform.validation.Validation +import org.amshove.kluent.`should be equal to` +import org.amshove.kluent.`should be instance of` +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Tags +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Execution(ExecutionMode.CONCURRENT) +@Tags(Tag("validation"), Tag("unit")) +internal class `Password Validation` { + @Test + fun password() { + "1234567890".passwordScore() `should be equal to` 10 + "1234567A".passwordScore() `should be equal to` 10 + "1234Aa".passwordScore() `should be equal to` 10 + "12Aab".passwordScore() `should be equal to` 11 + "1234Aa".passwordScore() `should be equal to` 10 + "12abCD-+".passwordScore() `should be equal to` 18 + "Abcde12!".passwordScore() `should be equal to` 15 + "Hello world".passwordScore() `should be equal to` 16 + } + + @Test + fun passwordScore() { + Validation { + ObjectToValid::password { + this.passwordScore(10) + } + }.run { + validate(ObjectToValid("1234567890")) `should be instance of` Valid::class + validate(ObjectToValid("12345678")) `should be instance of` Invalid::class + } + } + + class ObjectToValid(val password: String) +}