Compare commits
2 Commits
e6a7af840a
...
90701dcdce
| Author | SHA1 | Date | |
|---|---|---|---|
| 90701dcdce | |||
| 8439782430 |
@ -21,7 +21,7 @@ RUN chown -R $APPLICATION_USER /app
|
|||||||
USER $APPLICATION_USER
|
USER $APPLICATION_USER
|
||||||
|
|
||||||
COPY --from=jdkbuilder /myjdk /myjdk
|
COPY --from=jdkbuilder /myjdk /myjdk
|
||||||
COPY simplenotes-app/build/libs/simplenotes-app-with-dependencies*.jar /app/simplenotes.jar
|
COPY app/build/libs/app-with-dependencies*.jar /app/simplenotes.jar
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
CMD [ \
|
CMD [ \
|
||||||
|
|||||||
@ -10,10 +10,10 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":simplenotes-domain"))
|
implementation(project(":domain"))
|
||||||
implementation(project(":simplenotes-types"))
|
implementation(project(":types"))
|
||||||
implementation(project(":simplenotes-config"))
|
implementation(project(":config"))
|
||||||
implementation(project(":simplenotes-views"))
|
implementation(project(":views"))
|
||||||
|
|
||||||
implementation(Libs.arrowCoreData)
|
implementation(Libs.arrowCoreData)
|
||||||
implementation(Libs.konform)
|
implementation(Libs.konform)
|
||||||
@ -14,5 +14,5 @@
|
|||||||
<logger name="com.zaxxer.hikari" level="INFO"/>
|
<logger name="com.zaxxer.hikari" level="INFO"/>
|
||||||
<logger name="org.flywaydb.core" level="INFO"/>
|
<logger name="org.flywaydb.core" level="INFO"/>
|
||||||
<logger name="io.micronaut" level="INFO"/>
|
<logger name="io.micronaut" level="INFO"/>
|
||||||
<logger name="io.micronaut.context.lifecycle" level="DEBUG"/>
|
<logger name="io.micronaut.context.lifecycle" level="INFO"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@ -1,13 +1,14 @@
|
|||||||
package be.simplenotes.app.filters.auth
|
package be.simplenotes.app.filters.auth
|
||||||
|
|
||||||
import be.simplenotes.app.filters.auth.JwtSource.Cookie
|
import be.simplenotes.app.filters.auth.JwtSource.Cookie
|
||||||
import be.simplenotes.domain.security.JwtPayloadExtractor
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import org.http4k.core.Filter
|
import org.http4k.core.Filter
|
||||||
import org.http4k.core.HttpHandler
|
import org.http4k.core.HttpHandler
|
||||||
import org.http4k.core.with
|
import org.http4k.core.with
|
||||||
|
|
||||||
class OptionalAuthFilter(
|
class OptionalAuthFilter(
|
||||||
private val extractor: JwtPayloadExtractor,
|
private val simpleJwt: SimpleJwt<LoggedInUser>,
|
||||||
private val lens: OptionalAuthLens,
|
private val lens: OptionalAuthLens,
|
||||||
private val source: JwtSource = Cookie,
|
private val source: JwtSource = Cookie,
|
||||||
) : Filter {
|
) : Filter {
|
||||||
@ -17,6 +18,6 @@ class OptionalAuthFilter(
|
|||||||
Cookie -> it.bearerTokenCookie()
|
Cookie -> it.bearerTokenCookie()
|
||||||
}
|
}
|
||||||
|
|
||||||
next(it.with(lens of token?.let { extractor(it) }))
|
next(it.with(lens of token?.let { simpleJwt.extract(it) }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
package be.simplenotes.app.filters.auth
|
package be.simplenotes.app.filters.auth
|
||||||
|
|
||||||
import be.simplenotes.app.extensions.redirect
|
import be.simplenotes.app.extensions.redirect
|
||||||
import be.simplenotes.domain.security.JwtPayloadExtractor
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import org.http4k.core.Filter
|
import org.http4k.core.Filter
|
||||||
import org.http4k.core.HttpHandler
|
import org.http4k.core.HttpHandler
|
||||||
import org.http4k.core.Response
|
import org.http4k.core.Response
|
||||||
@ -9,7 +10,7 @@ import org.http4k.core.Status.Companion.UNAUTHORIZED
|
|||||||
import org.http4k.core.with
|
import org.http4k.core.with
|
||||||
|
|
||||||
class RequiredAuthFilter(
|
class RequiredAuthFilter(
|
||||||
private val extractor: JwtPayloadExtractor,
|
private val simpleJwt: SimpleJwt<LoggedInUser>,
|
||||||
private val lens: RequiredAuthLens,
|
private val lens: RequiredAuthLens,
|
||||||
private val source: JwtSource = JwtSource.Cookie,
|
private val source: JwtSource = JwtSource.Cookie,
|
||||||
private val redirect: Boolean = true,
|
private val redirect: Boolean = true,
|
||||||
@ -19,7 +20,7 @@ class RequiredAuthFilter(
|
|||||||
JwtSource.Header -> it.bearerTokenHeader()
|
JwtSource.Header -> it.bearerTokenHeader()
|
||||||
JwtSource.Cookie -> it.bearerTokenCookie()
|
JwtSource.Cookie -> it.bearerTokenCookie()
|
||||||
}
|
}
|
||||||
val jwtPayload = token?.let { extractor(token) }
|
val jwtPayload = token?.let { simpleJwt.extract(token) }
|
||||||
|
|
||||||
if (jwtPayload != null) next(it.with(lens of jwtPayload))
|
if (jwtPayload != null) next(it.with(lens of jwtPayload))
|
||||||
else {
|
else {
|
||||||
@ -1,7 +1,8 @@
|
|||||||
package be.simplenotes.app.modules
|
package be.simplenotes.app.modules
|
||||||
|
|
||||||
import be.simplenotes.app.filters.auth.*
|
import be.simplenotes.app.filters.auth.*
|
||||||
import be.simplenotes.domain.security.JwtPayloadExtractor
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import io.micronaut.context.annotation.Factory
|
import io.micronaut.context.annotation.Factory
|
||||||
import io.micronaut.context.annotation.Primary
|
import io.micronaut.context.annotation.Primary
|
||||||
import org.http4k.core.RequestContexts
|
import org.http4k.core.RequestContexts
|
||||||
@ -21,21 +22,21 @@ class AuthModule {
|
|||||||
fun requiredAuthLens(ctx: RequestContexts): RequiredAuthLens = RequestContextKey.required(ctx)
|
fun requiredAuthLens(ctx: RequestContexts): RequiredAuthLens = RequestContextKey.required(ctx)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
fun optionalAuth(extractor: JwtPayloadExtractor, @Named("optional") lens: OptionalAuthLens) =
|
fun optionalAuth(simpleJwt: SimpleJwt<LoggedInUser>, @Named("optional") lens: OptionalAuthLens) =
|
||||||
OptionalAuthFilter(extractor, lens)
|
OptionalAuthFilter(simpleJwt, lens)
|
||||||
|
|
||||||
@Primary
|
@Primary
|
||||||
@Singleton
|
@Singleton
|
||||||
fun requiredAuth(extractor: JwtPayloadExtractor, @Named("required") lens: RequiredAuthLens) =
|
fun requiredAuth(simpleJwt: SimpleJwt<LoggedInUser>, @Named("required") lens: RequiredAuthLens) =
|
||||||
RequiredAuthFilter(extractor, lens)
|
RequiredAuthFilter(simpleJwt, lens)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("api")
|
@Named("api")
|
||||||
internal fun apiAuthFilter(
|
internal fun apiAuthFilter(
|
||||||
jwtPayloadExtractor: JwtPayloadExtractor,
|
simpleJwt: SimpleJwt<LoggedInUser>,
|
||||||
@Named("required") lens: RequiredAuthLens,
|
@Named("required") lens: RequiredAuthLens,
|
||||||
) = RequiredAuthFilter(
|
) = RequiredAuthFilter(
|
||||||
extractor = jwtPayloadExtractor,
|
simpleJwt = simpleJwt,
|
||||||
lens = lens,
|
lens = lens,
|
||||||
source = JwtSource.Header,
|
source = JwtSource.Header,
|
||||||
redirect = false
|
redirect = false
|
||||||
1
app/test/Index.kt
Normal file
@ -0,0 +1 @@
|
|||||||
|
package be.simplenotes.app
|
||||||
@ -6,6 +6,7 @@ import be.simplenotes.app.filters.auth.RequiredAuthFilter
|
|||||||
import be.simplenotes.app.filters.auth.RequiredAuthLens
|
import be.simplenotes.app.filters.auth.RequiredAuthLens
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.domain.security.SimpleJwt
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
|
import be.simplenotes.domain.security.UserJwtMapper
|
||||||
import be.simplenotes.types.LoggedInUser
|
import be.simplenotes.types.LoggedInUser
|
||||||
import com.natpryce.hamkrest.assertion.assertThat
|
import com.natpryce.hamkrest.assertion.assertThat
|
||||||
import io.micronaut.context.BeanContext
|
import io.micronaut.context.BeanContext
|
||||||
@ -32,7 +33,7 @@ internal class RequiredAuthFilterTest {
|
|||||||
|
|
||||||
// region setup
|
// region setup
|
||||||
private val jwtConfig = JwtConfig("secret", 1, TimeUnit.HOURS)
|
private val jwtConfig = JwtConfig("secret", 1, TimeUnit.HOURS)
|
||||||
private val simpleJwt = SimpleJwt(jwtConfig)
|
private val simpleJwt = SimpleJwt(jwtConfig, UserJwtMapper())
|
||||||
|
|
||||||
private val beanCtx = BeanContext.build()
|
private val beanCtx = BeanContext.build()
|
||||||
.registerSingleton(jwtConfig)
|
.registerSingleton(jwtConfig)
|
||||||
@ -15,15 +15,15 @@ open class CssTask : DefaultTask() {
|
|||||||
|
|
||||||
private val viewsProject = project
|
private val viewsProject = project
|
||||||
.parent
|
.parent
|
||||||
?.project(":simplenotes-views")
|
?.project(":views")
|
||||||
?: error("Missing :simplenotes-views")
|
?: error("Missing :views")
|
||||||
|
|
||||||
@get:InputDirectory
|
@get:InputDirectory
|
||||||
val templatesDir = viewsProject.extensions
|
val templatesDir = viewsProject.extensions
|
||||||
.getByType<SourceSetContainer>()
|
.getByType<SourceSetContainer>()
|
||||||
.asMap.getOrElse("main") { error("main sources not found") }
|
.asMap.getOrElse("main") { error("main sources not found") }
|
||||||
.allSource.srcDirs
|
.allSource.srcDirs
|
||||||
.find { it.endsWith("kotlin") }
|
.find { it.endsWith("src") }
|
||||||
?: error("kotlin sources not found")
|
?: error("kotlin sources not found")
|
||||||
|
|
||||||
private val yarnRoot = File(project.rootDir, "css")
|
private val yarnRoot = File(project.rootDir, "css")
|
||||||
|
|||||||
@ -24,3 +24,6 @@ java {
|
|||||||
tasks.withType<JavaCompile> {
|
tasks.withType<JavaCompile> {
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets["main"].resources.srcDirs("resources")
|
||||||
|
sourceSets["test"].resources.srcDirs("testresources")
|
||||||
|
|||||||
@ -10,5 +10,5 @@ tasks.withType<Test> {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
val test by getting
|
val test by getting
|
||||||
test.resources.srcDir("${rootProject.projectDir}/simplenotes-test-resources/src/test/resources")
|
test.resources.srcDir("${rootProject.projectDir}/testresources/src/test/resources")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,3 +23,6 @@ tasks.withType<KotlinCompile> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin.sourceSets["main"].kotlin.srcDirs("src")
|
||||||
|
kotlin.sourceSets["test"].kotlin.srcDirs("test")
|
||||||
|
|||||||
@ -7,10 +7,10 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":simplenotes-config"))
|
implementation(project(":config"))
|
||||||
implementation(project(":simplenotes-types"))
|
implementation(project(":types"))
|
||||||
implementation(project(":simplenotes-persistance"))
|
implementation(project(":persistance"))
|
||||||
implementation(project(":simplenotes-search"))
|
implementation(project(":search"))
|
||||||
|
|
||||||
implementation(Libs.micronaut)
|
implementation(Libs.micronaut)
|
||||||
kapt(Libs.micronautProcessor)
|
kapt(Libs.micronautProcessor)
|
||||||
1
domain/src/Index.kt
Normal file
@ -0,0 +1 @@
|
|||||||
|
package be.simplenotes.domain
|
||||||
30
domain/src/security/JwtMapper.kt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package be.simplenotes.domain.security
|
||||||
|
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
|
import com.auth0.jwt.JWTCreator
|
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
interface JwtMapper<T> {
|
||||||
|
fun extract(decodedJWT: DecodedJWT): T?
|
||||||
|
fun build(builder: JWTCreator.Builder, value: T)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class UserJwtMapper : JwtMapper<LoggedInUser> {
|
||||||
|
private val userIdField = "i"
|
||||||
|
private val usernameField = "u"
|
||||||
|
|
||||||
|
override fun extract(decodedJWT: DecodedJWT): LoggedInUser? {
|
||||||
|
val id = decodedJWT.getClaim(userIdField).asInt() ?: null
|
||||||
|
val username = decodedJWT.getClaim(usernameField).asString() ?: null
|
||||||
|
return if (id != null && username != null)
|
||||||
|
LoggedInUser(id, username)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun build(builder: JWTCreator.Builder, value: LoggedInUser) {
|
||||||
|
builder.withClaim(userIdField, value.userId)
|
||||||
|
.withClaim(usernameField, value.username)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +1,33 @@
|
|||||||
package be.simplenotes.domain.security
|
package be.simplenotes.domain.security
|
||||||
|
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.types.LoggedInUser
|
|
||||||
import com.auth0.jwt.JWT
|
import com.auth0.jwt.JWT
|
||||||
import com.auth0.jwt.JWTVerifier
|
import com.auth0.jwt.JWTVerifier
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
|
import com.auth0.jwt.exceptions.JWTVerificationException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
internal const val userIdField = "i"
|
|
||||||
internal const val usernameField = "u"
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class SimpleJwt(jwtConfig: JwtConfig) {
|
class SimpleJwt<T>(jwtConfig: JwtConfig, private val mapper: JwtMapper<T>) {
|
||||||
private val validityInMs = TimeUnit.MILLISECONDS.convert(jwtConfig.validity, jwtConfig.timeUnit)
|
private val validityInMs = TimeUnit.MILLISECONDS.convert(jwtConfig.validity, jwtConfig.timeUnit)
|
||||||
private val algorithm = Algorithm.HMAC256(jwtConfig.secret)
|
private val algorithm = Algorithm.HMAC256(jwtConfig.secret)
|
||||||
|
private val verifier: JWTVerifier = JWT.require(algorithm).build()
|
||||||
|
|
||||||
val verifier: JWTVerifier = JWT.require(algorithm).build()
|
fun sign(value: T): String = JWT.create()
|
||||||
fun sign(loggedInUser: LoggedInUser): String = JWT.create()
|
.apply { mapper.build(this, value) }
|
||||||
.withClaim(userIdField, loggedInUser.userId)
|
|
||||||
.withClaim(usernameField, loggedInUser.username)
|
|
||||||
.withExpiresAt(getExpiration())
|
.withExpiresAt(getExpiration())
|
||||||
.sign(algorithm)
|
.sign(algorithm)
|
||||||
|
|
||||||
|
fun extract(token: String): T? = try {
|
||||||
|
val decodedJWT = verifier.verify(token)
|
||||||
|
mapper.extract(decodedJWT)
|
||||||
|
} catch (e: JWTVerificationException) {
|
||||||
|
null
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
private fun getExpiration() = Date(System.currentTimeMillis() + validityInMs)
|
private fun getExpiration() = Date(System.currentTimeMillis() + validityInMs)
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@ import javax.inject.Singleton
|
|||||||
internal class LoginUseCaseImpl(
|
internal class LoginUseCaseImpl(
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val passwordHash: PasswordHash,
|
private val passwordHash: PasswordHash,
|
||||||
private val jwt: SimpleJwt
|
private val jwt: SimpleJwt<LoggedInUser>
|
||||||
) : LoginUseCase {
|
) : LoginUseCase {
|
||||||
override fun login(form: LoginForm) = either.eager<LoginError, Token> {
|
override fun login(form: LoginForm) = either.eager<LoginError, Token> {
|
||||||
val user = !UserValidations.validateLogin(form)
|
val user = !UserValidations.validateLogin(form)
|
||||||
1
domain/test/Index.kt
Normal file
@ -0,0 +1 @@
|
|||||||
|
package be.simplenotes.domain
|
||||||
@ -16,14 +16,13 @@ import java.util.stream.Stream
|
|||||||
|
|
||||||
internal class LoggedInUserExtractorTest {
|
internal class LoggedInUserExtractorTest {
|
||||||
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
||||||
private val simpleJwt = SimpleJwt(jwtConfig)
|
private val mapper = UserJwtMapper()
|
||||||
private val jwtPayloadExtractor = JwtPayloadExtractor(simpleJwt)
|
private val simpleJwt = SimpleJwt(jwtConfig, mapper)
|
||||||
|
|
||||||
private fun createToken(username: String? = null, id: Int? = null, secret: String = jwtConfig.secret): Token {
|
private fun createToken(username: String? = null, id: Int? = null, secret: String = jwtConfig.secret): Token {
|
||||||
val algo = Algorithm.HMAC256(secret)
|
val algo = Algorithm.HMAC256(secret)
|
||||||
return JWT.create().apply {
|
return JWT.create().apply {
|
||||||
username?.let { withClaim(usernameField, it) }
|
if (username != null && id != null) mapper.build(this, LoggedInUser(id, username))
|
||||||
id?.let { withClaim(userIdField, it) }
|
|
||||||
}.sign(algo)
|
}.sign(algo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +39,12 @@ internal class LoggedInUserExtractorTest {
|
|||||||
@ParameterizedTest(name = "[{index}] token `{0}` should be invalid")
|
@ParameterizedTest(name = "[{index}] token `{0}` should be invalid")
|
||||||
@MethodSource("invalidTokens")
|
@MethodSource("invalidTokens")
|
||||||
fun `parse invalid tokens`(token: String) {
|
fun `parse invalid tokens`(token: String) {
|
||||||
assertThat(jwtPayloadExtractor(token), absent())
|
assertThat(simpleJwt.extract(token), absent())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `parse valid token`() {
|
fun `parse valid token`() {
|
||||||
val token = createToken(username = "someone", id = 1)
|
val token = createToken(username = "someone", id = 1)
|
||||||
assertThat(jwtPayloadExtractor(token), equalTo(LoggedInUser(1, "someone")))
|
assertThat(simpleJwt.extract(token), equalTo(LoggedInUser(1, "someone")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ package be.simplenotes.domain.usecases.users.login
|
|||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.domain.security.BcryptPasswordHash
|
import be.simplenotes.domain.security.BcryptPasswordHash
|
||||||
import be.simplenotes.domain.security.SimpleJwt
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
|
import be.simplenotes.domain.security.UserJwtMapper
|
||||||
import be.simplenotes.domain.testutils.isLeftOfType
|
import be.simplenotes.domain.testutils.isLeftOfType
|
||||||
import be.simplenotes.domain.testutils.isRight
|
import be.simplenotes.domain.testutils.isRight
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
@ -18,7 +19,7 @@ internal class LoginUseCaseImplTest {
|
|||||||
private val mockUserRepository = mockk<UserRepository>()
|
private val mockUserRepository = mockk<UserRepository>()
|
||||||
private val passwordHash = BcryptPasswordHash(test = true)
|
private val passwordHash = BcryptPasswordHash(test = true)
|
||||||
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
||||||
private val simpleJwt = SimpleJwt(jwtConfig)
|
private val simpleJwt = SimpleJwt(jwtConfig, UserJwtMapper())
|
||||||
private val loginUseCase = LoginUseCaseImpl(mockUserRepository, passwordHash, simpleJwt)
|
private val loginUseCase = LoginUseCaseImpl(mockUserRepository, passwordHash, simpleJwt)
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@ -7,8 +7,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":simplenotes-types"))
|
implementation(project(":types"))
|
||||||
implementation(project(":simplenotes-config"))
|
implementation(project(":config"))
|
||||||
|
|
||||||
implementation(Libs.mariadbClient)
|
implementation(Libs.mariadbClient)
|
||||||
implementation(Libs.h2)
|
implementation(Libs.h2)
|
||||||
@ -29,9 +29,9 @@ dependencies {
|
|||||||
testImplementation(Libs.logbackClassic)
|
testImplementation(Libs.logbackClassic)
|
||||||
testImplementation(Libs.mariaTestContainer)
|
testImplementation(Libs.mariaTestContainer)
|
||||||
|
|
||||||
testFixturesImplementation(project(":simplenotes-types"))
|
testFixturesImplementation(project(":types"))
|
||||||
testFixturesImplementation(project(":simplenotes-config"))
|
testFixturesImplementation(project(":config"))
|
||||||
testFixturesImplementation(project(":simplenotes-persistance"))
|
testFixturesImplementation(project(":persistance"))
|
||||||
|
|
||||||
testFixturesImplementation(Libs.micronaut)
|
testFixturesImplementation(Libs.micronaut)
|
||||||
kaptTestFixtures(Libs.micronautProcessor)
|
kaptTestFixtures(Libs.micronautProcessor)
|
||||||
@ -48,3 +48,5 @@ dependencies {
|
|||||||
testFixturesImplementation(Libs.ktormCore)
|
testFixturesImplementation(Libs.ktormCore)
|
||||||
testFixturesImplementation(Libs.hikariCP)
|
testFixturesImplementation(Libs.hikariCP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin.sourceSets["testFixtures"].kotlin.srcDirs("testfixtures")
|
||||||