diff --git a/build.gradle.kts b/build.gradle.kts index 2a646ba..e602d99 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("org.springframework.boot") version "2.4.1" - id("io.spring.dependency-management") version "1.0.10.RELEASE" + id("org.springframework.boot") version "2.5.0-M3" + id("io.spring.dependency-management") version "1.0.11.RELEASE" war - kotlin("jvm") version "1.4.21" - kotlin("plugin.spring") version "1.4.21" - kotlin("plugin.jpa") version "1.4.21" + kotlin("jvm") version "1.4.31" + kotlin("plugin.spring") version "1.4.31" + kotlin("plugin.jpa") version "1.4.31" } group = "eu.fosil" @@ -15,23 +15,33 @@ java.sourceCompatibility = JavaVersion.VERSION_11 repositories { mavenCentral() + maven { url = uri("https://repo.spring.io/milestone") } } dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") - implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") + + + implementation("com.nimbusds:nimbus-jose-jwt:8.20.2") + implementation("com.nimbusds:oauth2-oidc-sdk:8.36.1") + implementation("org.springframework.security:spring-security-oauth2-jose:5.4.5") + // https://mvnrepository.com/artifact/net.folivo/matrix-spring-boot-bot - implementation ("net.folivo:matrix-spring-boot-bot:0.4.6") +// implementation ("net.folivo:matrix-spring-boot-bot:0.4.6") developmentOnly("org.springframework.boot:spring-boot-devtools") runtimeOnly("com.h2database:h2") - runtimeOnly("io.r2dbc:r2dbc-h2") - providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") +// runtimeOnly("io.r2dbc:r2dbc-h2") +// providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("io.projectreactor:reactor-test") } tasks.withType { diff --git a/settings.gradle.kts b/settings.gradle.kts index f7c4106..66deae9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,7 @@ -rootProject.name = "okupamicoche" +pluginManagement { + repositories { + maven { url = uri("https://repo.spring.io/milestone") } + gradlePluginPortal() + } +} +rootProject . name = "okupamicoche" diff --git a/src/main/kotlin/eu/fosil/okupamicoche/spring/OkupaMiCocheApplication.kt b/src/main/kotlin/eu/fosil/okupamicoche/OkupaMiCocheApplication.kt similarity index 68% rename from src/main/kotlin/eu/fosil/okupamicoche/spring/OkupaMiCocheApplication.kt rename to src/main/kotlin/eu/fosil/okupamicoche/OkupaMiCocheApplication.kt index 18bab4c..9c60656 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/spring/OkupaMiCocheApplication.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/OkupaMiCocheApplication.kt @@ -1,13 +1,14 @@ -package eu.fosil.okupamicoche.spring +package eu.fosil.okupamicoche import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.runApplication import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.web.reactive.config.EnableWebFlux @SpringBootApplication -@EnableJpaRepositories("eu.fosil.okupamicoche.*") -@EntityScan("eu.fosil.okupamicoche.*") +//@EnableJpaRepositories("eu.fosil.okupamicoche.*") +//@EntityScan("eu.fosil.okupamicoche.*") class OkupaMiCocheApplication fun main(args: Array) { diff --git a/src/main/kotlin/eu/fosil/okupamicoche/entities/Travel.kt b/src/main/kotlin/eu/fosil/okupamicoche/entities/Travel.kt index 052c97a..ca13fc4 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/entities/Travel.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/entities/Travel.kt @@ -9,7 +9,7 @@ class Travel( @Id @GeneratedValue var id: TravelId? = null, @ManyToOne var driver: User, - @ManyToMany + @ManyToMany(fetch = FetchType.EAGER) // https://stackoverflow.com/questions/22821695/how-to-fix-hibernate-lazyinitializationexception-failed-to-lazily-initialize-a var travelers: MutableList, var departureDate: String, var origin: String, diff --git a/src/main/kotlin/eu/fosil/okupamicoche/spring/ServletInitializer.kt b/src/main/kotlin/eu/fosil/okupamicoche/spring/ServletInitializer.kt index 2bec19a..ea8c54e 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/spring/ServletInitializer.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/spring/ServletInitializer.kt @@ -1,5 +1,6 @@ package eu.fosil.okupamicoche.spring +import eu.fosil.okupamicoche.OkupaMiCocheApplication import org.springframework.boot.builder.SpringApplicationBuilder import org.springframework.boot.web.servlet.support.SpringBootServletInitializer diff --git a/src/main/kotlin/eu/fosil/okupamicoche/spring/conf/WebSecurityConfig.kt b/src/main/kotlin/eu/fosil/okupamicoche/spring/conf/WebSecurityConfig.kt index e09ea8e..e67e244 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/spring/conf/WebSecurityConfig.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/spring/conf/WebSecurityConfig.kt @@ -1,33 +1,47 @@ package eu.fosil.okupamicoche.spring.conf +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter -import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.reactive.CorsWebFilter +import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource +import org.springframework.web.reactive.config.CorsRegistry +import org.springframework.web.reactive.config.EnableWebFlux +import org.springframework.web.reactive.config.WebFluxConfigurer -@Configuration -class JWTSecurityConfig : WebSecurityConfigurerAdapter() { - @Throws(Exception::class) - override fun configure(http: HttpSecurity) {//@formatter:off - http.cors() - .and() - .csrf().disable() - .authorizeRequests() - .antMatchers("/api/public/**").permitAll() - .antMatchers("/api/user/**").authenticated() - .antMatchers("/api/travel/**").authenticated() - .anyRequest().denyAll() - .and() - .oauth2ResourceServer() - .jwt() +@EnableWebFluxSecurity +@EnableReactiveMethodSecurity +class SecurityConfig { + @Bean + fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {//@formatter:off + http + .authorizeExchange { exchanges -> + exchanges + .pathMatchers("/_matrix/**").permitAll() + .pathMatchers("/api/public/**").permitAll() + .pathMatchers("/api/user/**").authenticated() + .pathMatchers("/api/travel/**").authenticated() + .anyExchange().denyAll() + } + .oauth2ResourceServer { oauth2ResourceServer -> + oauth2ResourceServer.jwt { jwt -> jwt } + } + return http.build() }//@formatter:on } @Configuration -class CorsConfigurer : WebMvcConfigurer { - override fun addCorsMappings(registry: CorsRegistry) { - registry.addMapping("/**").allowedOrigins("http://localhost:4200") +@EnableWebFlux +class CorsGlobalConfiguration : WebFluxConfigurer { + override fun addCorsMappings(corsRegistry: CorsRegistry) { + corsRegistry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("PUT", "GET", "POST") + .maxAge(3600) } -} +} \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/spring/controller/PublicRestController.kt b/src/main/kotlin/eu/fosil/okupamicoche/spring/controller/PublicRestController.kt index 2848ede..d1b9a1b 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/spring/controller/PublicRestController.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/spring/controller/PublicRestController.kt @@ -12,10 +12,13 @@ import org.springframework.web.bind.annotation.CrossOrigin import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import reactor.core.publisher.Mono @RestController @RequestMapping("/api/public") -@CrossOrigin(origins = ["http://localhost:4200"]) +@CrossOrigin(value = [ "http://allowed-origin.com"], + maxAge = 900 +) class PublicRestController(private val travelRepository: TravelRepository) : ApiRestController { @RequestMapping("/list") @@ -25,20 +28,20 @@ class PublicRestController(private val travelRepository: TravelRepository) : Api @RequestParam @Validated sortAscending: Boolean?, @RequestParam @Validated pageIndex: Int?, @RequestParam @Validated pageSize: Int?, - ): ApiResponse> { - return response { + ): Mono>> { + return Mono.just(response { val travels = ListTravels(travelRepository).listTravels( filter, sortColumn, sortAscending, pageIndex, pageSize ).map { t -> TravelDto(t) } ListDto(travelRepository.count(), travels) - } + }) } @RequestMapping("/travel") - suspend fun getTravel(@RequestParam @Validated travelId: TravelId): ApiResponse { - return response { + suspend fun getTravel(@RequestParam @Validated travelId: TravelId): Mono> { + return Mono.just(response { travelRepository.findByIdOrNull(travelId)?.let { TravelDto(it) } - } + }) } } \ No newline at end of file diff --git a/src/main/kotlin/eu/fosil/okupamicoche/spring/services/MatrixService.kt b/src/main/kotlin/eu/fosil/okupamicoche/spring/services/MatrixService.kt index f1963f8..1519cdf 100644 --- a/src/main/kotlin/eu/fosil/okupamicoche/spring/services/MatrixService.kt +++ b/src/main/kotlin/eu/fosil/okupamicoche/spring/services/MatrixService.kt @@ -3,30 +3,33 @@ package eu.fosil.okupamicoche.spring.services import eu.fosil.okupamicoche.entities.User import eu.fosil.okupamicoche.usecases.matrix.MatrixApi import mu.KotlinLogging -import net.folivo.matrix.core.model.MatrixId -import net.folivo.matrix.restclient.MatrixClient +//import net.folivo.matrix.core.model.MatrixId +//import net.folivo.matrix.restclient.MatrixClient import org.springframework.stereotype.Service import java.util.stream.Collectors @Service -class MatrixService(private val matrixClient: MatrixClient): MatrixApi { +class MatrixService( +// private val matrixClient: MatrixClient + ): MatrixApi { private val logger = KotlinLogging.logger {} override suspend fun createRoom(name: String, alias: String, usersToInvite: Set, topic: String?): String { logger.debug { "Creating room name=$name alias=$alias" } - val usersToInviteId = usersToInvite.stream().map { user -> MatrixId.UserId(user.matrixId) } - val roomId = matrixClient.roomsApi.createRoom( - name = name, - roomAliasId = MatrixId.RoomAliasId("#$alias:synapse"), -// invite = usersToInviteId.collect(Collectors.toSet()), - topic = topic - ) - return roomId.full +// val usersToInviteId = usersToInvite.stream().map { user -> MatrixId.UserId(user.matrixId) } +// val roomId = matrixClient.roomsApi.createRoom( +// name = name, +// roomAliasId = MatrixId.RoomAliasId("#$alias:synapse"), +//// invite = usersToInviteId.collect(Collectors.toSet()), +// topic = topic +// ) +// return roomId.full + return "0" } override suspend fun inviteUser(roomId: String, user: User) { - val matrixUserId = MatrixId.UserId(user.matrixId) - logger.debug { "Invite user $matrixUserId to room $roomId" } - matrixClient.roomsApi.inviteUser(MatrixId.RoomId(roomId), matrixUserId) +// val matrixUserId = MatrixId.UserId(user.matrixId) +// logger.debug { "Invite user $matrixUserId to room $roomId" } +// matrixClient.roomsApi.inviteUser(MatrixId.RoomId(roomId), matrixUserId) } } \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fa412f9..64ee596 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -18,52 +18,53 @@ spring: logging: level: eu.fosil.okupamicoche: DEBUG + net.folivo.matrix: DEBUG -matrix: - bot: - # The domain-part of matrix-ids. E. g. example.org when your userIds look like @unicorn:example.org - serverName: synapse - # The localpart (username) of the user associated with the application service - # or just the username of your bot. - username: okupamicoche - # (optional) Display name for the bot user. - displayname: Okupa mi coche - # (optional) The mode you want to use to create a bot. Default is CLIENT. The other is APPSERVICE. - mode: APPSERVICE - # (optional) Configure how users managed by your bot do automatically join rooms. - # ENABLED allows automatic joins to every invited room. - # DISABLED disables this feature. - # Default is RESTRICTED, which means, that only automatic joins to serverName are allowed. - autoJoin: DISABLED - # (optional) Configure if ALL membership changes should be tracked/saved with help of MatrixAppserviceRoomService - # or only membership changes of users, which are MANAGED by the bridge. Default is ALL (no tracking/saving). - trackMembership: ALL - # Connection setting to the database for migration purpose only (only jdbc drivers ar supported) - migration: - url: jdbc:h2:file:./matrix - username: sa - password: - # Connection settings to the database (only r2dbc drivers are supported) - database: - url: r2dbc:h2:file:///./matrix - username: sa - password: - client: - homeServer: - # The hostname of your Homeserver. - hostname: synapse - # (optional) The port of your Homeserver. Default is 443. - port: 8008 - # (optional) Use http or https. Default is true (so uses https). - secure: false - # The token to authenticate against the Homeserver. - token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" - appservice: - # A unique token for Homeservers to use to authenticate requests to application services. - hsToken: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" - # A list of users, aliases and rooms namespaces that the application service controls. - namespaces: - users: [ ] - aliases: - - localpartRegex: "viaje_.*" - rooms: [ ] \ No newline at end of file +#matrix: +# bot: +# # The domain-part of matrix-ids. E. g. example.org when your userIds look like @unicorn:example.org +# serverName: synapse +# # The localpart (username) of the user associated with the application service +# # or just the username of your bot. +# username: okupamicoche +# # (optional) Display name for the bot user. +# displayname: Okupa mi coche +# # (optional) The mode you want to use to create a bot. Default is CLIENT. The other is APPSERVICE. +# mode: APPSERVICE +# # (optional) Configure how users managed by your bot do automatically join rooms. +# # ENABLED allows automatic joins to every invited room. +# # DISABLED disables this feature. +# # Default is RESTRICTED, which means, that only automatic joins to serverName are allowed. +# autoJoin: DISABLED +# # (optional) Configure if ALL membership changes should be tracked/saved with help of MatrixAppserviceRoomService +# # or only membership changes of users, which are MANAGED by the bridge. Default is ALL (no tracking/saving). +# trackMembership: ALL +# # Connection setting to the database for migration purpose only (only jdbc drivers ar supported) +# migration: +# url: jdbc:h2:file:./matrix +# username: sa +# password: +# # Connection settings to the database (only r2dbc drivers are supported) +# database: +# url: r2dbc:h2:file:///./matrix +# username: sa +# password: +# client: +# homeServer: +# # The hostname of your Homeserver. +# hostname: synapse +# # (optional) The port of your Homeserver. Default is 443. +# port: 8008 +# # (optional) Use http or https. Default is true (so uses https). +# secure: false +# # The token to authenticate against the Homeserver. +# token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" +# appservice: +# # A unique token for Homeservers to use to authenticate requests to application services. +# hsToken: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" +# # A list of users, aliases and rooms namespaces that the application service controls. +# namespaces: +# users: [ ] +# aliases: +# - localpartRegex: "viaje_.*" +# rooms: [ ] \ No newline at end of file