101 lines
3.4 KiB
Kotlin
101 lines
3.4 KiB
Kotlin
package space.luminic.finance.api
|
|
|
|
|
|
import org.apache.commons.codec.digest.DigestUtils.sha256
|
|
import org.apache.commons.codec.digest.HmacUtils.hmacSha256
|
|
import org.slf4j.LoggerFactory
|
|
import org.springframework.beans.factory.annotation.Value
|
|
import org.springframework.security.core.context.SecurityContextHolder
|
|
import org.springframework.web.bind.annotation.*
|
|
import space.luminic.finance.dtos.UserDTO
|
|
import space.luminic.finance.dtos.UserDTO.AuthUserDTO
|
|
import space.luminic.finance.dtos.UserDTO.RegisterUserDTO
|
|
import space.luminic.finance.mappers.UserMapper.toDto
|
|
import space.luminic.finance.mappers.UserMapper.toTelegramMap
|
|
import space.luminic.finance.services.AuthService
|
|
import java.security.MessageDigest
|
|
import java.time.Instant
|
|
import javax.crypto.Mac
|
|
import javax.crypto.spec.SecretKeySpec
|
|
|
|
@RestController
|
|
@RequestMapping("/auth")
|
|
class AuthController(
|
|
private val authService: AuthService,
|
|
@Value("\${telegram.bot.token}") private val botToken: String
|
|
) {
|
|
|
|
private val logger = LoggerFactory.getLogger(javaClass)
|
|
|
|
fun verifyTelegramAuth(data: Map<String, String>, botToken: String): Boolean {
|
|
val hash = data["hash"] ?: return false
|
|
|
|
val dataCheckString = data
|
|
.filterKeys { it != "hash" }
|
|
.toSortedMap()
|
|
.map { "${it.key}=${it.value}" }
|
|
.joinToString("\n")
|
|
|
|
val secretKey = sha256(botToken)
|
|
val hmacHex = hmacSha256(secretKey, dataCheckString)
|
|
|
|
if (hmacHex != hash) return false
|
|
|
|
val authDate = data["auth_date"]?.toLongOrNull() ?: return false
|
|
val now = Instant.now().epochSecond
|
|
|
|
// Опционально — запрет старых ответов (например, старше 1 часа)
|
|
val maxAgeSeconds = 3600
|
|
if (now - authDate > maxAgeSeconds) return false
|
|
|
|
return true
|
|
}
|
|
|
|
private fun sha256(input: String): ByteArray =
|
|
MessageDigest.getInstance("SHA-256").digest(input.toByteArray())
|
|
|
|
private fun hmacSha256(secret: ByteArray, message: String): String {
|
|
val key = SecretKeySpec(secret, "HmacSHA256")
|
|
val mac = Mac.getInstance("HmacSHA256")
|
|
mac.init(key)
|
|
val hashBytes = mac.doFinal(message.toByteArray())
|
|
return hashBytes.joinToString("") { "%02x".format(it) }
|
|
}
|
|
|
|
@GetMapping("/test")
|
|
fun test(): String {
|
|
val authentication = SecurityContextHolder.getContext().authentication
|
|
logger.info("SecurityContext in controller: $authentication")
|
|
return "Hello, ${authentication.name}"
|
|
}
|
|
|
|
@PostMapping("/login")
|
|
fun login(@RequestBody request: AuthUserDTO): Map<String, String> {
|
|
val token = authService.login(request.username.lowercase(), request.password)
|
|
return mapOf("token" to token)
|
|
}
|
|
|
|
@PostMapping("/register")
|
|
fun register(@RequestBody request: RegisterUserDTO): UserDTO {
|
|
return authService.register(request.username, request.password, request.firstName).toDto()
|
|
}
|
|
|
|
@PostMapping("/tg-login")
|
|
fun tgLogin(@RequestBody tgUser: UserDTO.TelegramAuthDTO): String {
|
|
val ok = verifyTelegramAuth(tgUser.toTelegramMap(), botToken)
|
|
if (!ok) throw IllegalArgumentException("Invalid Telegram login")
|
|
return authService.tgAuth(tgUser)
|
|
|
|
}
|
|
|
|
|
|
|
|
@GetMapping("/me")
|
|
fun getMe(): UserDTO {
|
|
logger.info("Get Me")
|
|
authService.getSecurityUser()
|
|
|
|
return authService.getSecurityUser().toDto()
|
|
}
|
|
}
|