added further tests to register page
continuous-integration/drone/push Build is passing Details

dev
Override-6 2 years ago
parent f3782f492d
commit bb14aef019

@ -30,6 +30,8 @@ import scala.collection.immutable.HashMap
object Authenticator:
private final val LOG = LogManager.getLogger("Authentification")
private final val ValidMailPattern = "^\\w+([.-]?\\w+)*@\\w+([.-]?\\w+)*(\\.\\w{2,3})+$".r
private final val ValidForenamePattern = "^[a-zA-Z\\u00C0-\\u017F-']+$".r
private final val ValidNamePattern = ValidForenamePattern
private final val ValidPasswordPattern = ".{6,}".r
case class JwtContent(uuid: UUID)
@ -85,10 +87,15 @@ class Authenticator(url: URL, key: PublicKey, algorithm: JwtAsymmetricAlgorithm)
val hash = hashPassword(password)
User(uuid, name, forename, hash, mail)
}
if (!ValidMailPattern.matches(mail))
ZIO.fail(InvalidEmail(s"email address did not satisfy regex pattern $ValidMailPattern"))
ZIO.fail(InvalidEmail(s"email address did not satisfy regex pattern"))
else if (!ValidPasswordPattern.matches(password))
ZIO.fail(InvalidPassword(s"password did not satisfy regex pattern $ValidPasswordPattern"))
ZIO.fail(InvalidPassword(s"password did not satisfy regex pattern"))
else if (!ValidForenamePattern.matches(forename))
ZIO.fail(InvalidForename(s"email address did not satisfy regex pattern"))
else if (!ValidNamePattern.matches(name))
ZIO.fail(InvalidName(s"password did not satisfy regex pattern"))
else for
_ <- findByMail(mail).none.orElse(ZIO.fail(UserAlreadyRegistered(s"an email address already exists for '$mail'")))
_ <- run(quote {

@ -9,3 +9,9 @@ case class InvalidEmail(msg: String) extends AuthException(msg)
case class UserNotFound(msg: String) extends AuthException(msg)
case class UserAlreadyRegistered(msg: String) extends AuthException(msg)
case class InvalidName(msg: String) extends AuthException(msg)
case class InvalidForename(msg: String) extends AuthException(msg)

@ -14,12 +14,6 @@ import scala.jdk.CollectionConverters.*
import scala.language.reflectiveCalls
object HandlerUtils {
def parseAttribute[V, T <: Json {def value: V}](json: Json, name: String, cursor: JsonCursor[Json, T]): Task[V] =
ZIO.fromEither(json.get[T](cursor).map(_.value))
.mapError(InvalidRequest(s"Missing or invalid field $name.", _))
def parseAttributeOpt[V, T <: Json {def value: V}](json: Json, name: String, cursor: JsonCursor[Json, T]) =
ZIO.fromEither(json.get[T](cursor).map(_.value)).option
def errorBody(errorType: String, msg: String) = Body.fromString(s"""{"error": "$errorType","msg": "$msg"}""")

@ -4,7 +4,7 @@ import org.apache.logging.log4j.{LogManager, Logger}
import org.tbasket.auth.Authenticator
import org.tbasket.data.User
import org.tbasket.error.*
import org.tbasket.handler.HandlerUtils.{errorBody, parseAttribute, parseRequestForm, search}
import org.tbasket.handler.HandlerUtils.{errorBody, parseRequestForm, search}
import zio.ZIO
import zio.http.model.{Cookie, Headers, Status}
import zio.http.{Body, Request, Response, model}
@ -42,6 +42,14 @@ object RegisterPageHandler extends PageHandler {
status = Status.ExpectationFailed,
body = errorBody("invalid password", msg)
))
case InvalidName(msg) => ZIO.attempt(Response(
status = Status.ExpectationFailed,
body = errorBody("invalid name", msg)
))
case InvalidForename(msg) => ZIO.attempt(Response(
status = Status.ExpectationFailed,
body = errorBody("invalid forename", msg)
))
case UserAlreadyRegistered(msg) =>
ZIO.attempt(Response(
status = Status.NotAcceptable,

@ -1,14 +1,23 @@
package org.tbasket.test
import io.netty.handler.codec.http.QueryStringEncoder
import org.tbasket.error.InvalidRequest
import zio.*
import zio.http.{Body, Response}
import zio.json.*
import zio.json.ast.Json
import zio.json.ast.{Json, JsonCursor}
import scala.language.implicitConversions
import scala.language.{implicitConversions, reflectiveCalls}
object TestUtils {
def parseAttribute[V, T <: Json {def value: V}](json: Json, cursor: JsonCursor[Json, T]): Task[V] =
ZIO.fromEither(json.get[T](cursor).map(_.value))
.mapError(InvalidRequest(s"Missing or invalid field $cursor.", _))
def parseAttributeOpt[V, T <: Json {def value: V}](json: Json, cursor: JsonCursor[Json, T]) =
ZIO.fromEither(json.get[T](cursor).map(_.value)).option
def getJsonBody(r: Response): Task[Json] = {
for
body <- r.body.asString

@ -7,9 +7,8 @@ import org.tbasket.data.{Database, DatabaseContext}
import org.tbasket.endpoint.Endpoint
import org.tbasket.endpoint.Endpoint.handle
import org.tbasket.error.*
import org.tbasket.handler.HandlerUtils.parseAttribute
import org.tbasket.handler.LoginPageHandler
import org.tbasket.test.TestUtils.{getJsonBody, makeFormBody}
import org.tbasket.test.TestUtils.*
import org.tbasket.test.{TestLayers, TestUtils}
import zio.*
import zio.http.*
@ -35,7 +34,7 @@ object LoginPageHandlerTests extends TBasketPageSpec("/login") {
for
response <- handle(Request.post(body, url))
json <- getJsonBody(response)
errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString)
errorType <- parseAttribute(json, JsonCursor.field("error").isString)
yield
assert(response)(hasField("status", _.status, equalTo(Status.BadRequest)))
&& assertTrue(errorType == "invalid request")
@ -49,7 +48,7 @@ object LoginPageHandlerTests extends TBasketPageSpec("/login") {
for
response <- handle(Request.post(makeFormBody("password" -> "bouhours", "email" -> "unknownaccount@gmail.com"), url))
json <- getJsonBody(response)
errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString)
errorType <- parseAttribute(json, JsonCursor.field("error").isString)
yield
//assert that the response error is of type unauthorized and headers are Location: /register
assert(response)(hasField("status", _.status, equalTo(Status.Found)))
@ -72,7 +71,7 @@ object LoginPageHandlerTests extends TBasketPageSpec("/login") {
_ <- TestClock.adjust(1.seconds)
response <- ZIO.fromFiber(fiber)
json <- getJsonBody(response)
errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString)
errorType <- parseAttribute(json, JsonCursor.field("error").isString)
yield
assert(response)(hasField("status", _.status, equalTo(Status.Unauthorized)))
&& assert(errorType)(equalTo("unauthorized"))

@ -1,7 +1,6 @@
package org.tbasket.test.pages
import org.tbasket.endpoint.Endpoint.handle
import org.tbasket.handler.HandlerUtils.{parseAttribute, parseAttributeOpt}
import org.tbasket.test.TestUtils
import org.tbasket.test.TestUtils.*
import org.tbasket.test.pages.RegisterPageHandlerTests.test
@ -9,8 +8,8 @@ import zio.*
import zio.http.*
import zio.http.model.{HeaderNames, Headers, Status}
import zio.json.ast.JsonCursor
import zio.test.*
import zio.test.Assertion.*
import zio.test.{assert, *}
object RegisterPageHandlerTests extends TBasketPageSpec("/register") {
@ -26,7 +25,7 @@ object RegisterPageHandlerTests extends TBasketPageSpec("/register") {
for
response <- handle(Request.post(body, url))
json <- getJsonBody(response)
errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString)
errorType <- parseAttribute(json, JsonCursor.field("error").isString)
yield
assert(response)(hasField("status", _.status, equalTo(Status.BadRequest)))
&& assertTrue(errorType.startsWith("invalid"))
@ -48,13 +47,49 @@ object RegisterPageHandlerTests extends TBasketPageSpec("/register") {
(for
resp <- handle(Request.post(makeFormBody("name" -> "tuaillon", "forename" -> "leo", "email" -> "leo.tuaillon@etu.uca.fr", "password" -> "bouhours"), url))
json <- getJsonBody(resp)
errorType <- parseAttributeOpt(json, "error", JsonCursor.field("error").isString)
errorType <- parseAttributeOpt(json, JsonCursor.field("error").isString)
yield
assert(resp)(hasField("status", _.status, equalTo(Status.NotAcceptable)))
&& assert(errorType)(isSome(equalTo("already registered")))
&& assert(resp)(hasField("headers", _.headers, contains(Headers.location("/login")))))
},
test("register bad email") {
for
resp <- handle(Request.post(makeFormBody("name" -> "tuaillon", "forename" -> "leo", "email" -> "leo.tuaillonbadmail", "password" -> "bouhours"), url))
json <- getJsonBody(resp)
errorType <- parseAttributeOpt(json, JsonCursor.field("error").isString)
yield
assert(resp)(hasField("status", _.status, equalTo(Status.ExpectationFailed)))
&& assert(errorType)(isSome(equalTo("invalid email")))
},
test("register bad password") {
for
resp <- handle(Request.post(makeFormBody("name" -> "tuaillon", "forename" -> "leo", "email" -> "leo.tuaillon@etu.uca.fr", "password" -> "1234"), url))
json <- getJsonBody(resp)
errorType <- parseAttributeOpt(json, JsonCursor.field("error").isString)
yield
assert(resp)(hasField("status", _.status, equalTo(Status.ExpectationFailed)))
&& assert(errorType)(isSome(equalTo("invalid password")))
},
test("register bad name") {
for
resp <- handle(Request.post(makeFormBody("name" -> "", "forename" -> "leo", "email" -> "leo.tuaillon@etu.uca.fr", "password" -> "bouhours"), url))
json <- getJsonBody(resp)
errorType <- parseAttributeOpt(json, JsonCursor.field("error").isString)
yield
assert(resp)(hasField("status", _.status, equalTo(Status.ExpectationFailed)))
&& assert(errorType)(isSome(equalTo("invalid name")))
},
test("register bad forename") {
for
resp <- handle(Request.post(makeFormBody("name" -> "tuaillon", "forename" -> "", "email" -> "leo.tuaillon@etu.uca.fr", "password" -> "bouhours"), url))
json <- getJsonBody(resp)
errorType <- parseAttributeOpt(json, JsonCursor.field("error").isString)
yield
assert(resp)(hasField("status", _.status, equalTo(Status.ExpectationFailed)))
&& assert(errorType)(isSome(equalTo("invalid forename")))
}
)
override def tspec = suite("/register page handler")(