From 20b9dcf1d5b03c87fc12cf11e3c4395e717e6c97 Mon Sep 17 00:00:00 2001 From: neviyn Date: Mon, 10 May 2021 22:49:58 +0100 Subject: [PATCH] Changed logins to have proper redirections --- .../kotlin/uk/co/neviyn/booru/Controller.kt | 64 +++++++--- .../kotlin/uk/co/neviyn/booru/Security.kt | 19 ++- src/main/resources/templates/fragments.html | 109 ++++++++++-------- src/main/resources/templates/login.html | 3 +- src/main/resources/templates/single.html | 9 +- 5 files changed, 138 insertions(+), 66 deletions(-) diff --git a/src/main/kotlin/uk/co/neviyn/booru/Controller.kt b/src/main/kotlin/uk/co/neviyn/booru/Controller.kt index 94634a5..b16e073 100644 --- a/src/main/kotlin/uk/co/neviyn/booru/Controller.kt +++ b/src/main/kotlin/uk/co/neviyn/booru/Controller.kt @@ -3,6 +3,7 @@ package uk.co.neviyn.booru import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest +import org.springframework.security.access.annotation.Secured import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.stereotype.Controller import org.springframework.ui.Model @@ -33,38 +34,68 @@ class BaseController } @GetMapping("/login") - fun login(model: Model, error: String?, logout: String?): String? { + fun login(model: Model, error: String?, logout: String?, @RequestParam redirect: String): String? { if (error != null) model.addAttribute("error", "Your username and password is invalid.") if (logout != null) model.addAttribute("message", "You have been logged out successfully.") + model.addAttribute("redirect", redirect) return "login" } } +fun userCanEdit(userDetails: CustomUserDetails?, image: Image): Boolean = + userDetails != null && (userDetails.authorities.any { it.authority == "ADMIN" } || userDetails.getId() == image.uploader.id) + @Controller @RequestMapping("/view/{id}") class SingleImageViewController @Autowired constructor( val imageRepository: ImageRepository, val tagRepository: TagRepository -){ +) { @GetMapping - fun viewSingleImage(@PathVariable id: Long, model: Model, @AuthenticationPrincipal userDetails: CustomUserDetails?) : String { + fun viewSingleImage(@PathVariable id: Long, model: Model, @AuthenticationPrincipal userDetails: CustomUserDetails?): String { val image = imageRepository.findById(id).get() val tagData = image.tags.sortedBy { it.tag } model.addAttribute("image", image) model.addAttribute("tags", tagData) model.addAttribute("title", tagData.joinToString { it.tag }) - model.addAttribute("isUploader", (userDetails != null && (userDetails.authorities.any { it.authority == "ADMIN" } || userDetails.getId() == image.uploader.id))) + model.addAttribute("isUploader", userCanEdit(userDetails, image)) return "single" } - @PostMapping("/removetag") + @PostMapping("/addtag") + @Secured @Transactional - fun removeTagFromImage(@PathVariable id: Long, @RequestParam("tagId") tagID: Long, model: Model, @AuthenticationPrincipal userDetails: CustomUserDetails?) : String { + fun addTagToImage( + @PathVariable id: Long, + @RequestParam("tagName") tagName: String, + model: Model, + @AuthenticationPrincipal userDetails: CustomUserDetails? + ): String { val image = imageRepository.findById(id).get() - if(userDetails == null || userDetails.getId() != image.uploader.id || !userDetails.authorities.any { it.authority == "ADMIN" }) return "redirect:/view/$id" + if (!userCanEdit(userDetails, image)) return "redirect:/view/$id" + var newTag = tagRepository.findByTagIs(tagName) ?: Tag(tag = tagName) + if (image.tags.contains(newTag)) return "redirect:/view/$id" // Don't add a tag that an image already has + newTag.amount += 1 + newTag = tagRepository.save(newTag) + image.tags.add(newTag) + imageRepository.save(image) + return "redirect:/view/$id" + } + + @PostMapping("/removetag") + @Secured + @Transactional + fun removeTagFromImage( + @PathVariable id: Long, + @RequestParam("tagId") tagID: Long, + model: Model, + @AuthenticationPrincipal userDetails: CustomUserDetails? + ): String { + val image = imageRepository.findById(id).get() + if (!userCanEdit(userDetails, image)) return "redirect:/view/$id" val targetTag = image.tags.find { it.id == tagID } - if(targetTag != null){ + if (targetTag != null) { targetTag.amount -= 1 tagRepository.save(targetTag) image.tags.remove(targetTag) @@ -127,13 +158,15 @@ class MemberController ) { @GetMapping - fun memberDetails(@AuthenticationPrincipal userDetails: CustomUserDetails, model: Model) : String { + fun memberDetails(@AuthenticationPrincipal userDetails: CustomUserDetails?, model: Model): String { + if (userDetails == null) return "redirect:/login?redirect=/user" val user = DisplayUser(userDetails.getId(), userDetails.username, userDetails.getEmail(), "", "") model.addAttribute("userData", user) return "user" } @PostMapping + @Secured fun updateLoggedInUser(@Valid @ModelAttribute userData: DisplayUser, @AuthenticationPrincipal userDetails: CustomUserDetails, model: Model): String { if (userData.id == userDetails.getId() && passwordEncoder().matches(userData.oldPassword, userDetails.password)) { val user = memberRepository.findById(userDetails.getId()).get() @@ -162,9 +195,13 @@ class UploadController ) { @GetMapping - fun showUploadPage(): String = "upload" + fun showUploadPage(@AuthenticationPrincipal userDetails: CustomUserDetails?): String { + if (userDetails == null) return "redirect:/login?redirect=/upload" + return "upload" + } @PostMapping + @Secured fun uploadFile( @AuthenticationPrincipal userDetails: CustomUserDetails, @RequestParam file: MultipartFile, @@ -183,12 +220,13 @@ class UploadController } @DeleteMapping("/d/{imageID}") + @Secured @Transactional - fun deleteUpload(@PathVariable imageID: Long, @AuthenticationPrincipal userDetails: CustomUserDetails) : String { + fun deleteUpload(@PathVariable imageID: Long, @AuthenticationPrincipal userDetails: CustomUserDetails): String { val target = imageRepository.findById(imageID) - if(target.isEmpty) return "gallery" // No image with ID + if (target.isEmpty) return "gallery" // No image with ID val rTarget = target.get() - return if(userDetails.authorities.any { it.authority == "ADMIN" } || rTarget.uploader.id == userDetails.getId()) { + return if (userDetails.authorities.any { it.authority == "ADMIN" } || rTarget.uploader.id == userDetails.getId()) { rTarget.tags.map { it.amount = it.amount - 1 } tagRepository.saveAll(rTarget.tags) imageRepository.deleteTagAssociations(rTarget.id) diff --git a/src/main/kotlin/uk/co/neviyn/booru/Security.kt b/src/main/kotlin/uk/co/neviyn/booru/Security.kt index c5a9c03..6e8e9c4 100644 --- a/src/main/kotlin/uk/co/neviyn/booru/Security.kt +++ b/src/main/kotlin/uk/co/neviyn/booru/Security.kt @@ -13,7 +13,12 @@ import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.web.authentication.AuthenticationSuccessHandler +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler import org.springframework.stereotype.Service +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + @Configuration class SecurityConfig @@ -21,9 +26,9 @@ class SecurityConfig val userDetailsService: CustomUserDetailsService ) : WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { - http.authorizeRequests().antMatchers("/upload/**", "/user/**").hasAuthority("USER") + http.authorizeRequests() .anyRequest().permitAll().and() - .formLogin().loginPage("/login").permitAll().and() + .formLogin().successHandler(RefererRedirectionAuthenticationSuccessHandler()).loginPage("/login").permitAll().and() .logout().logoutSuccessUrl("/").permitAll().and() .httpBasic() } @@ -65,4 +70,12 @@ class CustomUserDetailsService } @Bean -fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder() \ No newline at end of file +fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder() + +// Keeps us on the same page when logging in +class RefererRedirectionAuthenticationSuccessHandler : SimpleUrlAuthenticationSuccessHandler(), AuthenticationSuccessHandler { + + override fun determineTargetUrl(request: HttpServletRequest?, response: HttpServletResponse?): String { + return request!!.getParameter("redirect") + } +} \ No newline at end of file diff --git a/src/main/resources/templates/fragments.html b/src/main/resources/templates/fragments.html index 7879a1d..8f32518 100644 --- a/src/main/resources/templates/fragments.html +++ b/src/main/resources/templates/fragments.html @@ -1,58 +1,73 @@ - +
- - - - - - - + + + + + + +
-
- -
- + +
-
-
- - -
-
- -
-
+
+
+ + +
+
+ +
+
\ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index dd94c28..abd7c0e 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -16,6 +16,7 @@

Uploaded by:

+
+ + + +