[O] Unwrap spaghetti code

pull/14/head
Azalea 2024-02-19 01:49:29 -05:00
parent 1e606f8b85
commit 4c3aafd266
3 changed files with 29 additions and 20 deletions

View File

@ -3,6 +3,7 @@ package icu.samnyan.aqua.net
import ext.* import ext.*
import icu.samnyan.aqua.net.db.AquaNetUser import icu.samnyan.aqua.net.db.AquaNetUser
import icu.samnyan.aqua.net.db.AquaNetUserRepo import icu.samnyan.aqua.net.db.AquaNetUserRepo
import icu.samnyan.aqua.net.utils.GeoIP
import icu.samnyan.aqua.net.utils.TurnstileService import icu.samnyan.aqua.net.utils.TurnstileService
import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletRequest
import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder
@ -15,7 +16,8 @@ import org.springframework.web.bind.annotation.RestController
class UserRegistrar( class UserRegistrar(
val userRepo: AquaNetUserRepo, val userRepo: AquaNetUserRepo,
val hasher: PasswordEncoder, val hasher: PasswordEncoder,
val turnstileService: TurnstileService val turnstileService: TurnstileService,
val geoIP: GeoIP
) { ) {
/** /**
* Register a new user * Register a new user
@ -23,8 +25,10 @@ class UserRegistrar(
@PostMapping("/register") @PostMapping("/register")
suspend fun register(@RP username: Str, @RP email: Str, @RP password: Str, suspend fun register(@RP username: Str, @RP email: Str, @RP password: Str,
@RP turnstile: Str?, request: HttpServletRequest) { @RP turnstile: Str?, request: HttpServletRequest) {
val ip = geoIP.getIP(request)
// Check captcha // Check captcha
if (!turnstileService.validate(turnstile, request)) 400 > "Invalid captcha" if (!turnstileService.validate(turnstile, ip)) 400 > "Invalid captcha"
// Check if email is valid // Check if email is valid
if (!email.isValidEmail()) 400 > "Invalid email" if (!email.isValidEmail()) 400 > "Invalid email"
@ -47,12 +51,14 @@ class UserRegistrar(
if (password.length < 8) 400 > "Password too short" if (password.length < 8) 400 > "Password too short"
// GeoIP check to infer country // GeoIP check to infer country
val country = geoIP.getCountry(ip)
val u = AquaNetUser(username = username, email = email, pwHash = hasher.encode(password), val u = AquaNetUser(username = username, email = email, pwHash = hasher.encode(password),
regTime = millis(), lastLogin = millis()) regTime = millis(), lastLogin = millis(), country = country)
async { userRepo.save(u) } async { userRepo.save(u) }
// TODO: Send confirmation email
200 > "User created" 200 > "User created"
} }
} }

View File

@ -2,7 +2,9 @@ package icu.samnyan.aqua.net.utils
import com.maxmind.geoip2.DatabaseReader import com.maxmind.geoip2.DatabaseReader
import ext.Bool import ext.Bool
import ext.Str
import jakarta.annotation.PostConstruct import jakarta.annotation.PostConstruct
import jakarta.servlet.http.HttpServletRequest
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
@ -16,9 +18,8 @@ import java.nio.file.Files
@Configuration @Configuration
@ConfigurationProperties(prefix = "aqua-net.geoip") @ConfigurationProperties(prefix = "aqua-net.geoip")
class GeoIPProperties { class GeoIPProperties {
var enable: Bool = false var geoLitePath: Str = "data/GeoLite2-Country.mmdb"
var ipHeader: Str = ""
lateinit var geoLitePath: String
} }
@Service @Service
@ -30,8 +31,6 @@ class GeoIP(
@PostConstruct @PostConstruct
fun onLoad() { fun onLoad() {
if (!props.enable) return
// Check path exists // Check path exists
if (!File(props.geoLitePath).exists()) { if (!File(props.geoLitePath).exists()) {
log.error("GeoIP Service is enabled but GeoLite2 database is not found, trying to download from GitHub.") log.error("GeoIP Service is enabled but GeoLite2 database is not found, trying to download from GitHub.")
@ -47,25 +46,33 @@ class GeoIP(
} }
geoLite = DatabaseReader.Builder(File(props.geoLitePath)).build() geoLite = DatabaseReader.Builder(File(props.geoLitePath)).build()
selfTest()
log.info("GeoIP Service Enabled")
}
// Self test /**
* Test the connection of the GeoIP service on startup
*/
fun selfTest() {
try { try {
getCountry("1.1.1.1") getCountry("1.1.1.1")
} catch (e: Exception) { } catch (e: Exception) {
log.error("GeoIP Service Self Test Failed", e) log.error("GeoIP Service Self Test Failed", e)
throw e throw e
} }
log.info("GeoIP Service Enabled")
} }
/**
* Get the IP address from a request
*/
fun getIP(request: HttpServletRequest): Str =
if (props.ipHeader.isEmpty()) request.remoteAddr else request.getHeader(props.ipHeader) ?: request.remoteAddr
/** /**
* Get the country code from an IP address * Get the country code from an IP address
*/ */
fun getCountry(ip: String): String fun getCountry(ip: Str): Str
{ {
if (!props.enable) return ""
return try { return try {
geoLite.country(InetAddress.getByName(ip)).country.isoCode geoLite.country(InetAddress.getByName(ip)).country.isoCode
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -19,8 +19,6 @@ class TurnstileProperties {
var enable: Bool = false var enable: Bool = false
lateinit var secret: Str lateinit var secret: Str
lateinit var ipHeader: Str
} }
@Service @Service
@ -28,12 +26,10 @@ class TurnstileService(val props: TurnstileProperties) {
@Serializable @Serializable
data class Outcome(val success: Boolean) data class Outcome(val success: Boolean)
suspend fun validate(captcha: Str?, request: HttpServletRequest): Boolean { suspend fun validate(captcha: Str?, ip: Str): Boolean {
if (!props.enable) return true if (!props.enable) return true
if (captcha == null) return false if (captcha == null) return false
val ip = request.getHeader(props.ipHeader) ?: request.remoteAddr
val outcome: Outcome = HTTP.post("https://challenges.cloudflare.com/turnstile/v0/siteverify") { val outcome: Outcome = HTTP.post("https://challenges.cloudflare.com/turnstile/v0/siteverify") {
setBody( setBody(
FormDataContent(Parameters.build { FormDataContent(Parameters.build {