~jan0sch/smederee

Showing details for patch c0fc9f2f7f044407becb7ef8802ecaf24f29f077.
2023-06-17 (Sat), 3:31 PM - Jens Grassel - c0fc9f2f7f044407becb7ef8802ecaf24f29f077

Change findLockedAccount to work with optional unlock token.

Change the findLockedAccount function in the AuthenticationRepository to work
with an optional unlock token parameter to ease administration work.

The function will now search for a locked user account with either the given
name or (if given) with the given name and the given token.
Summary of changes
4 files modified with 27 lines added and 8 lines removed
  • modules/hub/src/main/scala/de/smederee/hub/AuthenticationRepository.scala with 2 added and 2 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/DoobieAuthenticationRepository.scala with 4 added and 3 removed lines
  • modules/hub/src/test/scala/de/smederee/hub/DoobieAuthenticationRepositoryTest.scala with 20 added and 2 removed lines
  • modules/hub/src/test/scala/de/smederee/hub/TestAuthenticationRepository.scala with 1 added and 1 removed lines
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/AuthenticationRepository.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/AuthenticationRepository.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/AuthenticationRepository.scala	2025-01-16 02:56:31.247039962 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/AuthenticationRepository.scala	2025-01-16 02:56:31.251039970 +0000
@@ -97,11 +97,11 @@
     * @param name
     *   The username which must be unique according to our requirements.
     * @param token
-    *   An unlock token which must be present.
+    *   An unlock token which must be present if given.
     * @return
     *   An option to the account if it exists and is locked using the given token.
     */
-  def findLockedAccount(name: Username)(token: UnlockToken): F[Option[Account]]
+  def findLockedAccount(name: Username)(token: Option[UnlockToken]): F[Option[Account]]
 
   /** Retrieve the password hash and the number of failed login attempts from the database.
     *
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/DoobieAuthenticationRepository.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/DoobieAuthenticationRepository.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/DoobieAuthenticationRepository.scala	2025-01-16 02:56:31.247039962 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/DoobieAuthenticationRepository.scala	2025-01-16 02:56:31.251039970 +0000
@@ -20,6 +20,7 @@
 import java.util.UUID
 
 import cats.effect._
+import cats.syntax.all._
 import de.smederee.email.EmailAddress
 import de.smederee.i18n.LanguageCode
 import de.smederee.security._
@@ -72,10 +73,10 @@
     query.query[Account].option.transact(tx)
   }
 
-  override def findLockedAccount(name: Username)(token: UnlockToken): F[Option[Account]] = {
+  override def findLockedAccount(name: Username)(token: Option[UnlockToken]): F[Option[Account]] = {
     val nameFilter  = fr"""name = $name"""
-    val tokenFilter = fr"""unlock_token = $token"""
-    val query       = selectAccountColumns ++ whereAnd(lockedFilter, nameFilter, tokenFilter) ++ fr"""LIMIT 1"""
+    val tokenFilter = token.map(token => fr"""unlock_token = $token""")
+    val query = selectAccountColumns ++ whereAndOpt(lockedFilter.some, nameFilter.some, tokenFilter) ++ fr"""LIMIT 1"""
     query.query[Account].option.transact(tx)
   }
 
diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieAuthenticationRepositoryTest.scala new-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieAuthenticationRepositoryTest.scala
--- old-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieAuthenticationRepositoryTest.scala	2025-01-16 02:56:31.247039962 +0000
+++ new-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieAuthenticationRepositoryTest.scala	2025-01-16 02:56:31.251039970 +0000
@@ -251,7 +251,25 @@
         val token    = UnlockToken.generate
         val test = for {
           _ <- createAccount(account, PasswordHash("I am not a password hash!"), Option(token), None)
-          o <- repo.findLockedAccount(account.name)(token)
+          o <- repo.findLockedAccount(account.name)(token.some)
+        } yield o
+        test.map { result =>
+          assert(result === Option(account))
+        }
+    }
+  }
+
+  test("findLockedAccount must return a locked account if no token is given".tag(NeedsDatabase)) {
+    genValidAccount.sample match {
+      case None => fail("Could not generate data samples!")
+      case Some(account) =>
+        val dbConfig = configuration.database
+        val tx       = Transactor.fromDriverManager[IO](dbConfig.driver, dbConfig.url, dbConfig.user, dbConfig.pass)
+        val repo     = new DoobieAuthenticationRepository[IO](tx)
+        val token    = UnlockToken.generate
+        val test = for {
+          _ <- createAccount(account, PasswordHash("I am not a password hash!"), Option(token), None)
+          o <- repo.findLockedAccount(account.name)(None)
         } yield o
         test.map { result =>
           assert(result === Option(account))
@@ -359,7 +377,7 @@
           before <- repo.findAccount(account.uid)
           _      <- repo.lockAccount(account.uid)(Option(token))
           after  <- repo.findAccount(account.uid)
-          locked <- repo.findLockedAccount(account.name)(token)
+          locked <- repo.findLockedAccount(account.name)(token.some)
         } yield (before, after, locked)
         test.map { result =>
           result match {
diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/hub/TestAuthenticationRepository.scala new-smederee/modules/hub/src/test/scala/de/smederee/hub/TestAuthenticationRepository.scala
--- old-smederee/modules/hub/src/test/scala/de/smederee/hub/TestAuthenticationRepository.scala	2025-01-16 02:56:31.247039962 +0000
+++ new-smederee/modules/hub/src/test/scala/de/smederee/hub/TestAuthenticationRepository.scala	2025-01-16 02:56:31.251039970 +0000
@@ -80,7 +80,7 @@
 
   override def findUserSession(id: SessionId): F[Option[Session]] = Sync[F].pure(sessions.headOption)
 
-  override def findLockedAccount(name: Username)(token: UnlockToken): F[Option[Account]] =
+  override def findLockedAccount(name: Username)(token: Option[UnlockToken]): F[Option[Account]] =
     Sync[F].pure(accounts.headOption)
 
   override def findPasswordHashAndAttempts(uid: UserId): F[Option[(PasswordHash, Int)]] =