feature/8-secure-without-content #10
|
@ -0,0 +1,11 @@
|
|||
.gradle
|
||||
.idea
|
||||
**/build
|
||||
**/data
|
||||
**/gradle
|
||||
**/logs
|
||||
.gitignore
|
||||
.gitlab-ci.yml
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
gradlew**
|
60
.drone.yml
60
.drone.yml
|
@ -1,38 +1,51 @@
|
|||
---
|
||||
global-variables:
|
||||
environment: &environment
|
||||
JAVA_VERSION: 11
|
||||
GRADLE_VERSION: 7.1
|
||||
CRE_VERSION: dev-${DRONE_BUILD_NUMBER}
|
||||
CRE_ARTIFACT_NAME: ColorRecipesExplorer
|
||||
CRE_REGISTRY_IMAGE: registry.fyloz.dev:5443/colorrecipesexplorer/backend
|
||||
CRE_PORT: 9101
|
||||
gradle-image: &gradle-image gradle:7.1-jdk11
|
||||
alpine-image: &alpine-image alpine:latest
|
||||
docker-registry-repo: &docker-registry-repo registry.fyloz.dev:5443/colorrecipesexplorer/backend
|
||||
|
||||
kind: pipeline
|
||||
name: default
|
||||
type: docker
|
||||
|
||||
environment:
|
||||
CRE_VERSION: ${DRONE_BUILD_NUMBER}
|
||||
CRE_ARTIFACT_NAME: ColorRecipesExplorer
|
||||
CRE_REGISTRY_IMAGE: registry.fyloz.dev:5443/colorrecipesexplorer/backend
|
||||
CRE_PORT: 9101
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: gradle:7.1-jdk11
|
||||
- name: set-docker-tags
|
||||
image: *alpine-image
|
||||
environment:
|
||||
<<: *environment
|
||||
commands:
|
||||
- gradle test
|
||||
- echo -n "latest,dev-$CRE_VERSION" > .tags
|
||||
- cat .tags
|
||||
when:
|
||||
branch: develop
|
||||
events: push
|
||||
|
||||
- name: build
|
||||
image: gradle:7.1-jdk11
|
||||
- name: gradle-test
|
||||
image: *gradle-image
|
||||
commands:
|
||||
- gradle bootJar -Pversion=$CRE_VERSION
|
||||
- mv build/libs/ColorRecipesExplorer-$CRE_VERSION.jar $CRE_ARTIFACT_NAME.jar
|
||||
- echo -n "latest,$CRE_VERSION" > .tags
|
||||
- gradle test
|
||||
when:
|
||||
branch: master
|
||||
events: push
|
||||
branch: develop
|
||||
events: [push, pull_request]
|
||||
|
||||
- name: containerize
|
||||
image: plugins/docker
|
||||
environment:
|
||||
<<: *environment
|
||||
settings:
|
||||
build_args:
|
||||
- JAVA_VERSION=11
|
||||
repo: registry.fyloz.dev:5443/colorrecipesexplorer/backend
|
||||
build_args_from_env:
|
||||
- GRADLE_VERSION
|
||||
- JAVA_VERSION
|
||||
- CRE_VERSION
|
||||
- CRE_PORT
|
||||
repo: *docker-registry-repo
|
||||
when:
|
||||
branch: master
|
||||
events: push
|
||||
|
@ -40,6 +53,8 @@ steps:
|
|||
- name: deploy
|
||||
image: alpine:latest
|
||||
environment:
|
||||
<<: *environment
|
||||
CRE_REGISTRY_IMAGE: *docker-registry-repo
|
||||
DEPLOY_SERVER:
|
||||
from_secret: deploy_server
|
||||
DEPLOY_SERVER_USERNAME:
|
||||
|
@ -64,9 +79,14 @@ steps:
|
|||
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
|
||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker stop $DEPLOY_CONTAINER_NAME || true && docker rm $DEPLOY_CONTAINER_NAME || true"
|
||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker pull $CRE_REGISTRY_IMAGE:latest"
|
||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker run -d -p $CRE_PORT:9090 --name=$DEPLOY_CONTAINER_NAME -v $DEPLOY_DATA_VOLUME:/usr/bin/cre/data -v $DEPLOY_CONFIG_VOLUME:/usr/bin/cre/config -e spring_profiles_active=$DEPLOY_SPRING_PROFILES $CRE_REGISTRY_IMAGE"
|
||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker run -d -p $CRE_PORT:9090 --name=$DEPLOY_CONTAINER_NAME -v $DEPLOY_DATA_VOLUME:/usr/bin/data -v $DEPLOY_CONFIG_VOLUME:/usr/bin/config -e spring_profiles_active=$DEPLOY_SPRING_PROFILES $CRE_REGISTRY_IMAGE"
|
||||
when:
|
||||
branch: master
|
||||
events: push
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- develop
|
||||
- master
|
||||
|
||||
|
||||
|
|
22
Dockerfile
22
Dockerfile
|
@ -1,11 +1,21 @@
|
|||
ARG GRADLE_VERSION=7.1
|
||||
ARG JAVA_VERSION=11
|
||||
ARG CRE_VERSION=dev
|
||||
|
||||
FROM openjdk:$JAVA_VERSION
|
||||
FROM gradle:$GRADLE_VERSION-jdk$JAVA_VERSION AS build
|
||||
WORKDIR /usr/src
|
||||
|
||||
WORKDIR /usr/bin/cre/
|
||||
COPY . .
|
||||
RUN gradle bootJar -Pversion=$CRE_VERSION
|
||||
|
||||
ARG CRE_ARTIFACT_NAME=ColorRecipesExplorer
|
||||
COPY $CRE_ARTIFACT_NAME.jar ColorRecipesExplorer.jar
|
||||
FROM alpine:latest
|
||||
WORKDIR /usr/bin
|
||||
|
||||
ARG JAVA_VERSION
|
||||
RUN apk add --no-cache openjdk$JAVA_VERSION
|
||||
|
||||
ARG CRE_VERSION
|
||||
COPY --from=build /usr/src/build/libs/ColorRecipesExplorer.jar ColorRecipesExplorer.jar
|
||||
|
||||
ARG CRE_PORT=9090
|
||||
EXPOSE $CRE_PORT
|
||||
|
@ -16,7 +26,7 @@ ENV spring_datasource_url=jdbc:h2:mem:cre
|
|||
ENV spring_datasource_username=root
|
||||
ENV spring_datasource_password=pass
|
||||
|
||||
VOLUME /usr/bin/cre/data
|
||||
VOLUME /usr/bin/cre/config
|
||||
VOLUME /usr/bin/data
|
||||
VOLUME /usr/bin/config
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "ColorRecipesExplorer.jar"]
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
ARG JDK_VERSION=11
|
||||
ARG GRADLE_VERSION=7.1
|
||||
|
||||
FROM gradle:$GRADLE_VERSION-jdk$JDK_VERSION
|
||||
WORKDIR /usr/src/cre/
|
||||
|
||||
COPY build.gradle.kts build.gradle.kts
|
||||
COPY settings.gradle.kts settings.gradle.kts
|
||||
COPY src src
|
||||
|
|
@ -3,23 +3,24 @@ package dev.fyloz.colorrecipesexplorer
|
|||
import dev.fyloz.colorrecipesexplorer.databasemanager.CreDatabase
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseContext
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseUpdaterProperties
|
||||
import dev.fyloz.colorrecipesexplorer.model.Configuration
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
|
||||
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.DependsOn
|
||||
import org.springframework.context.annotation.Profile
|
||||
import org.springframework.core.env.ConfigurableEnvironment
|
||||
import javax.sql.DataSource
|
||||
import org.springframework.context.annotation.Configuration as SpringConfiguration
|
||||
|
||||
const val SUPPORTED_DATABASE_VERSION = 5
|
||||
const val ENV_VAR_ENABLE_DATABASE_UPDATE_NAME = "CRE_ENABLE_DB_UPDATE"
|
||||
val DATABASE_NAME_REGEX = Regex("(\\w+)$")
|
||||
|
||||
@Profile("!emergency")
|
||||
@Configuration
|
||||
@SpringConfiguration
|
||||
@DependsOn("configurationsInitializer", "configurationService")
|
||||
class DataSourceConfiguration {
|
||||
@Bean(name = ["dataSource"])
|
||||
|
@ -29,7 +30,8 @@ class DataSourceConfiguration {
|
|||
configurationService: ConfigurationService
|
||||
): DataSource {
|
||||
fun getConfiguration(type: ConfigurationType) =
|
||||
configurationService.get(type).content
|
||||
if (type.secure) configurationService.getSecure(type)
|
||||
else configurationService.getContent(type)
|
||||
|
||||
val databaseUrl = "jdbc:" + getConfiguration(ConfigurationType.DATABASE_URL)
|
||||
val databaseUsername = getConfiguration(ConfigurationType.DATABASE_USER)
|
||||
|
|
|
@ -12,20 +12,25 @@ import javax.persistence.Id
|
|||
import javax.persistence.Table
|
||||
import javax.validation.constraints.NotBlank
|
||||
|
||||
data class Configuration(
|
||||
sealed class ConfigurationBase(
|
||||
@JsonIgnore
|
||||
val type: ConfigurationType,
|
||||
val content: String,
|
||||
val lastUpdated: LocalDateTime
|
||||
) {
|
||||
val key = type.key
|
||||
val requireRestart = type.requireRestart
|
||||
val editable = !type.computed
|
||||
}
|
||||
|
||||
class Configuration(type: ConfigurationType, val content: String, lastUpdated: LocalDateTime) :
|
||||
ConfigurationBase(type, lastUpdated) {
|
||||
fun toEntity() =
|
||||
ConfigurationEntity(key, content, lastUpdated)
|
||||
}
|
||||
|
||||
class SecureConfiguration(type: ConfigurationType, lastUpdated: LocalDateTime) :
|
||||
ConfigurationBase(type, lastUpdated)
|
||||
|
||||
@Entity
|
||||
@Table(name = "configuration")
|
||||
data class ConfigurationEntity(
|
||||
|
@ -76,6 +81,15 @@ fun configuration(
|
|||
configuration(type = key.toConfigurationType(), content = content)
|
||||
}
|
||||
|
||||
fun secureConfiguration(
|
||||
type: ConfigurationType,
|
||||
lastUpdated: LocalDateTime? = null
|
||||
) = SecureConfiguration(type, lastUpdated ?: LocalDateTime.now())
|
||||
|
||||
fun secureConfiguration(
|
||||
configuration: Configuration
|
||||
) = secureConfiguration(configuration.type, configuration.lastUpdated)
|
||||
|
||||
enum class ConfigurationType(
|
||||
val key: String,
|
||||
val defaultContent: Any? = null,
|
||||
|
@ -92,7 +106,13 @@ enum class ConfigurationType(
|
|||
|
||||
DATABASE_URL("database.url", defaultContent = "mysql://localhost/cre", file = true, requireRestart = true),
|
||||
DATABASE_USER("database.user", defaultContent = "cre", file = true, requireRestart = true),
|
||||
DATABASE_PASSWORD("database.password", defaultContent = "asecurepassword", file = true, requireRestart = true, secure = true),
|
||||
DATABASE_PASSWORD(
|
||||
"database.password",
|
||||
defaultContent = "asecurepassword",
|
||||
file = true,
|
||||
requireRestart = true,
|
||||
secure = true
|
||||
),
|
||||
DATABASE_SUPPORTED_VERSION("database.version.supported", computed = true),
|
||||
|
||||
RECIPE_APPROBATION_EXPIRATION("recipe.approbation.expiration", defaultContent = 4.months),
|
||||
|
@ -128,15 +148,15 @@ class InvalidConfigurationKeyException(val key: String) :
|
|||
)
|
||||
|
||||
class InvalidImageConfigurationException(val type: ConfigurationType) :
|
||||
RestException(
|
||||
"invalid-configuration-image",
|
||||
"Invalid image configuration",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The configuration with the key '${type.key}' does not accept images as content",
|
||||
mapOf(
|
||||
"key" to type.key
|
||||
)
|
||||
)
|
||||
RestException(
|
||||
"invalid-configuration-image",
|
||||
"Invalid image configuration",
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"The configuration with the key '${type.key}' does not accept images as content",
|
||||
mapOf(
|
||||
"key" to type.key
|
||||
)
|
||||
)
|
||||
|
||||
class ConfigurationNotSetException(val type: ConfigurationType) :
|
||||
RestException(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.model.Configuration
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationBase
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationImageDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.Permission
|
||||
|
@ -20,13 +20,11 @@ class ConfigurationController(val configurationService: ConfigurationService) {
|
|||
fun getAll(@RequestParam(required = false) keys: String?, authentication: Authentication?) =
|
||||
ok(with(configurationService) {
|
||||
if (keys != null) getAll(keys) else getAll()
|
||||
}.filter {
|
||||
!it.type.secure && authentication.hasAuthority(it)
|
||||
})
|
||||
}.filter { authentication.hasAuthority(it) })
|
||||
|
||||
@GetMapping("{key}")
|
||||
fun get(@PathVariable key: String, authentication: Authentication?) = with(configurationService.get(key)) {
|
||||
if (!this.type.secure && authentication.hasAuthority(this)) ok(this) else forbidden()
|
||||
if (authentication.hasAuthority(this)) ok(this) else forbidden()
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
|
@ -48,7 +46,7 @@ class ConfigurationController(val configurationService: ConfigurationService) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun Authentication?.hasAuthority(configuration: Configuration) = when {
|
||||
private fun Authentication?.hasAuthority(configuration: ConfigurationBase) = when {
|
||||
configuration.type.public -> true
|
||||
this != null && Permission.ADMIN.toAuthority() in this.authorities -> true
|
||||
else -> false
|
||||
|
|
|
@ -59,7 +59,7 @@ class MaterialServiceImpl(
|
|||
isMixType = this.isMixType,
|
||||
materialType = this.materialType!!,
|
||||
simdutUrl = if (fileService.exists(this.simdutFilePath))
|
||||
"${configService.get(ConfigurationType.INSTANCE_URL).content}$FILE_CONTROLLER_PATH?path=${
|
||||
"${configService.getContent(ConfigurationType.INSTANCE_URL)}$FILE_CONTROLLER_PATH?path=${
|
||||
URLEncoder.encode(
|
||||
this.simdutFilePath,
|
||||
StandardCharsets.UTF_8
|
||||
|
|
|
@ -78,7 +78,7 @@ class RecipeServiceImpl(
|
|||
}.toSet(),
|
||||
this.groupsInformation,
|
||||
recipeImageService.getAllImages(this)
|
||||
.map { this.imageUrl(configService.get(ConfigurationType.INSTANCE_URL).content, it) }
|
||||
.map { this.imageUrl(configService.getContent(ConfigurationType.INSTANCE_URL), it) }
|
||||
.toSet()
|
||||
)
|
||||
|
||||
|
@ -87,7 +87,7 @@ class RecipeServiceImpl(
|
|||
repository.existsByNameAndCompany(name, company)
|
||||
|
||||
override fun isApprobationExpired(recipe: Recipe): Boolean? =
|
||||
with(Period.parse(configService.get(ConfigurationType.RECIPE_APPROBATION_EXPIRATION).content)) {
|
||||
with(Period.parse(configService.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION))) {
|
||||
recipe.approbationDate?.plus(this)?.isBefore(LocalDate.now())
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class TouchUpKitServiceImpl(
|
|||
touchUpKitRepository
|
||||
), TouchUpKitService {
|
||||
private val cacheGeneratedFiles by lazy {
|
||||
configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF).content == true.toString()
|
||||
configService.getContent(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) == true.toString()
|
||||
}
|
||||
|
||||
override fun idNotFoundException(id: Long) = touchUpKitIdNotFoundException(id)
|
||||
|
@ -90,7 +90,7 @@ class TouchUpKitServiceImpl(
|
|||
}
|
||||
|
||||
override fun isExpired(touchUpKit: TouchUpKit) =
|
||||
with(Period.parse(configService.get(ConfigurationType.TOUCH_UP_KIT_EXPIRATION).content)) {
|
||||
with(Period.parse(configService.getContent(ConfigurationType.TOUCH_UP_KIT_EXPIRATION))) {
|
||||
touchUpKit.completed && touchUpKit.completionDate!!.plus(this) < LocalDate.now()
|
||||
}
|
||||
|
||||
|
@ -144,5 +144,5 @@ class TouchUpKitServiceImpl(
|
|||
"$TOUCH_UP_KIT_FILES_PATH/$this.pdf"
|
||||
|
||||
private fun TouchUpKit.pdfUrl() =
|
||||
"${configService.get(ConfigurationType.INSTANCE_URL).content}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
|
||||
"${configService.getContent(ConfigurationType.INSTANCE_URL)}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
|
||||
}
|
||||
|
|
|
@ -12,22 +12,28 @@ import org.springframework.stereotype.Service
|
|||
|
||||
interface ConfigurationService {
|
||||
/** Gets all set configurations. */
|
||||
fun getAll(): List<Configuration>
|
||||
fun getAll(): List<ConfigurationBase>
|
||||
|
||||
/**
|
||||
* Gets all configurations with keys contained in the given [formattedKeyList].
|
||||
* The [formattedKeyList] contains wanted configuration keys separated by a semi-colon.
|
||||
*/
|
||||
fun getAll(formattedKeyList: String): List<Configuration>
|
||||
fun getAll(formattedKeyList: String): List<ConfigurationBase>
|
||||
|
||||
/**
|
||||
* Gets the configuration with the given [key].
|
||||
* If the [key] does not exists, an [InvalidConfigurationKeyException] will be thrown.
|
||||
*/
|
||||
fun get(key: String): Configuration
|
||||
fun get(key: String): ConfigurationBase
|
||||
|
||||
/** Gets the configuration with the given [type]. */
|
||||
fun get(type: ConfigurationType): Configuration
|
||||
fun get(type: ConfigurationType): ConfigurationBase
|
||||
|
||||
/** Gets the content of the configuration with the given [type]. */
|
||||
fun getContent(type: ConfigurationType): String
|
||||
|
||||
/** Gets the content of the secure configuration with the given [type]. Should not be accessible to the users. */
|
||||
fun getSecure(type: ConfigurationType): String
|
||||
|
||||
/** Sets the content of each configuration in the given [configurations] list. */
|
||||
fun set(configurations: List<ConfigurationDto>)
|
||||
|
@ -89,18 +95,32 @@ class ConfigurationServiceImpl(
|
|||
override fun get(key: String) =
|
||||
get(key.toConfigurationType())
|
||||
|
||||
override fun get(type: ConfigurationType): Configuration {
|
||||
override fun get(type: ConfigurationType): ConfigurationBase {
|
||||
// Encryption salt should never be returned, but cannot be set as "secure" without encrypting it
|
||||
if (type == ConfigurationType.GENERATED_ENCRYPTION_SALT) throw InvalidConfigurationKeyException(type.key)
|
||||
|
||||
val configuration = configurationSource.get(type) ?: throw ConfigurationNotSetException(type)
|
||||
return if (type.secure) {
|
||||
decryptConfiguration(configuration)
|
||||
secureConfiguration(configuration)
|
||||
} else {
|
||||
configuration
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContent(type: ConfigurationType): String {
|
||||
val configuration = get(type)
|
||||
if (configuration is SecureConfiguration) throw UnsupportedOperationException("Cannot get '${type.key}' configuration content because it is secure")
|
||||
|
||||
return (configuration as Configuration).content
|
||||
}
|
||||
|
||||
override fun getSecure(type: ConfigurationType): String {
|
||||
if (!type.secure) throw UnsupportedOperationException("Cannot get configuration of type '${type.key}' because it is not a secure configuration")
|
||||
|
||||
val configuration = configurationSource.get(type) ?: throw ConfigurationNotSetException(type)
|
||||
return decryptConfiguration(configuration).content
|
||||
}
|
||||
|
||||
override fun set(configurations: List<ConfigurationDto>) {
|
||||
configurationSource.set(
|
||||
configurations
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.mockk.*
|
|||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.UnsupportedOperationException
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
@ -165,7 +166,47 @@ class ConfigurationServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `get(type) decrypts configuration content when the given ConfigurationType is secure`() {
|
||||
fun `get(type) returns a SecureConfiguration when the given ConfigurationType is secure`() {
|
||||
val type = ConfigurationType.DATABASE_PASSWORD
|
||||
val configuration = configuration(
|
||||
type = type,
|
||||
content = "securepassword".encrypt(type.key, securityProperties.configSalt!!)
|
||||
)
|
||||
|
||||
every { configurationSource.get(type) } returns configuration
|
||||
|
||||
val found = service.get(type)
|
||||
|
||||
assertTrue { found is SecureConfiguration }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getContent(type) returns configuration content`() {
|
||||
val type = ConfigurationType.INSTANCE_NAME
|
||||
val configuration = configuration(
|
||||
type = type,
|
||||
content = "content"
|
||||
)
|
||||
|
||||
every { service.get(type) } returns configuration
|
||||
|
||||
val found = service.getContent(type)
|
||||
|
||||
assertEquals(configuration.content, found)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getContent(type) throws UnsupportedOperationException when configuration is secure`() {
|
||||
val type = ConfigurationType.DATABASE_PASSWORD
|
||||
val configuration = secureConfiguration(type)
|
||||
|
||||
every { service.get(type) } returns configuration
|
||||
|
||||
assertThrows<UnsupportedOperationException> { service.getContent(type) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSecure(type) returns decrypted configuration content`() {
|
||||
val type = ConfigurationType.DATABASE_PASSWORD
|
||||
val content = "securepassword"
|
||||
val configuration = configuration(
|
||||
|
@ -175,9 +216,16 @@ class ConfigurationServiceTest {
|
|||
|
||||
every { configurationSource.get(type) } returns configuration
|
||||
|
||||
val found = service.get(type)
|
||||
val found = service.getSecure(type)
|
||||
|
||||
assertEquals(content, found.content)
|
||||
assertEquals(content, found)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSecure(type) throws UnsupportedOperationException when configuration is not secure`() {
|
||||
val type = ConfigurationType.INSTANCE_NAME
|
||||
|
||||
assertThrows<UnsupportedOperationException> { service.getSecure(type) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -197,7 +245,7 @@ class ConfigurationServiceTest {
|
|||
fun `set(configuration) encrypts secure configurations`() {
|
||||
val type = ConfigurationType.DATABASE_PASSWORD
|
||||
val content = "securepassword"
|
||||
val encryptedContent =content.encrypt(type.key, securityProperties.configSalt!!)
|
||||
val encryptedContent = content.encrypt(type.key, securityProperties.configSalt!!)
|
||||
val configuration = configuration(type = type, content = content)
|
||||
|
||||
mockkStatic(String::encrypt)
|
||||
|
|
|
@ -80,9 +80,9 @@ class RecipeServiceTest :
|
|||
@Test
|
||||
fun `isApprobationExpired() returns false when the approbation date of the given recipe is within the configured period`() {
|
||||
val period = Period.ofMonths(4)
|
||||
val config = configuration(type = ConfigurationType.RECIPE_APPROBATION_EXPIRATION, content = period.toString())
|
||||
val recipe = recipe(approbationDate = LocalDate.now())
|
||||
whenever(configService.get(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(config)
|
||||
|
||||
whenever(configService.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(period.toString())
|
||||
|
||||
val approbationExpired = service.isApprobationExpired(recipe)
|
||||
|
||||
|
@ -93,9 +93,9 @@ class RecipeServiceTest :
|
|||
@Test
|
||||
fun `isApprobationExpired() returns true when the approbation date of the given recipe is outside the configured period`() {
|
||||
val period = Period.ofMonths(4)
|
||||
val config = configuration(type = ConfigurationType.RECIPE_APPROBATION_EXPIRATION, content = period.toString())
|
||||
val recipe = recipe(approbationDate = LocalDate.now().minus(period).minusMonths(1))
|
||||
whenever(configService.get(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(config)
|
||||
|
||||
whenever(configService.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(period.toString())
|
||||
|
||||
val approbationExpired = service.isApprobationExpired(recipe)
|
||||
|
||||
|
@ -106,9 +106,9 @@ class RecipeServiceTest :
|
|||
@Test
|
||||
fun `isApprobationExpired() returns null when the given recipe as no approbation date`() {
|
||||
val period = Period.ofMonths(4)
|
||||
val config = configuration(type = ConfigurationType.RECIPE_APPROBATION_EXPIRATION, content = period.toString())
|
||||
val recipe = recipe(approbationDate = null)
|
||||
whenever(configService.get(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(config)
|
||||
|
||||
whenever(configService.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION)).doReturn(period.toString())
|
||||
|
||||
val approbationExpired = service.isApprobationExpired(recipe)
|
||||
|
||||
|
|
|
@ -131,10 +131,7 @@ class TouchUpKitServiceTest {
|
|||
this.setCachePdf(false)
|
||||
|
||||
private fun TouchUpKitServiceTestContext.setCachePdf(enabled: Boolean) {
|
||||
every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(
|
||||
type = ConfigurationType.TOUCH_UP_KIT_CACHE_PDF,
|
||||
enabled.toString()
|
||||
)
|
||||
every { configService.getContent(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns enabled.toString()
|
||||
}
|
||||
|
||||
private fun test(test: TouchUpKitServiceTestContext.() -> Unit) {
|
||||
|
|
15
todo.txt
15
todo.txt
|
@ -1,15 +0,0 @@
|
|||
== Icônes pour recettes non-approuvés / quantité faible ==
|
||||
== Texte SIMDUT inexistant (fiche signalitique) pour les matériaux ==
|
||||
|
||||
|
||||
|
||||
== Comptes ==
|
||||
No employé - Permissions - Employés
|
||||
|
||||
|
||||
|
||||
== Kits de retouche ==
|
||||
No Job - No Dossier - Qté - Description - Case à cocher - Note
|
||||
Bouton compléter si tout est coché/imprimé ?
|
||||
|
||||
Enregistrer localdatetime/personne pendant une certaine durée
|
Loading…
Reference in New Issue