[O] Refactor AimeDB

pull/14/head
Azalea 2024-02-22 20:55:13 -05:00
parent 30a7fa7ead
commit 8f250e755e
19 changed files with 234 additions and 725 deletions

View File

@ -0,0 +1 @@
package icu.samnyan.aqua.sega.aimedb

View File

@ -1,6 +1,5 @@
package icu.samnyan.aqua.sega.aimedb
import icu.samnyan.aqua.sega.aimedb.exception.InvalidRequestException
import icu.samnyan.aqua.sega.aimedb.util.Encryption
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
@ -25,7 +24,7 @@ class AimeDbDecoder : ByteToMessageDecoder() {
* @param ctx ChannelHandlerContext
* @param input ByteBuf in
* @param out List<Object>
</Object> */
*/
@Throws(Exception::class)
override fun decode(ctx: ChannelHandlerContext, input: ByteBuf, out: MutableList<Any>) {
if (input.readableBytes() < 16) return

View File

@ -1,96 +0,0 @@
package icu.samnyan.aqua.sega.aimedb;
import icu.samnyan.aqua.sega.aimedb.handler.impl.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.AllArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope("prototype")
@AllArgsConstructor
public class AimeDbRequestHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LoggerFactory.getLogger(AimeDbRequestHandler.class);
private final CampaignHandler campaignHandler;
private final FeliCaLookupHandler feliCaLookupHandler;
private final FeliCaLookup2Handler feliCaLookup2Handler;
private final GoodbyeHandler goodbyeHandler;
private final HelloHandler helloHandler;
private final LogHandler logHandler;
private final LookupHandler lookupHandler;
private final Lookup2Handler lookup2Handler;
private final RegisterHandler registerHandler;
private final Unknown19Handler unknown19Handler;
private final TouchHandler touchHandler;
@Override
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception {
if (msg instanceof Map) {
int type = ((int) ((Map<?, ?>) msg).get("type"));
ByteBuf data = (ByteBuf) ((Map<?, ?>) msg).get("data");
switch (type) {
case 0x0001:
feliCaLookupHandler.handle(ctx, data);
break;
case 0x0004:
lookupHandler.handle(ctx, data);
break;
case 0x0005:
registerHandler.handle(ctx, data);
break;
case 0x0009:
logHandler.handle(ctx, data);
break;
case 0x000b:
campaignHandler.handle(ctx, data);
break;
case 0x000d:
touchHandler.handle(ctx, data);
break;
case 0x000f:
lookup2Handler.handle(ctx, data);
break;
case 0x0011:
feliCaLookup2Handler.handle(ctx, data);
break;
case 0x0013:
unknown19Handler.handle(ctx, data);
break;
case 0x0064:
helloHandler.handle(ctx, data);
break;
case 0x0066:
goodbyeHandler.handle(ctx, data);
break;
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error("Error in AimeDB", cause);
ctx.close();
}
@Override
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
logger.debug("Connection closed");
}
}

View File

@ -0,0 +1,231 @@
package icu.samnyan.aqua.sega.aimedb
import icu.samnyan.aqua.sega.general.model.Card
import icu.samnyan.aqua.sega.general.service.CardService
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component
import java.nio.charset.StandardCharsets
import kotlin.jvm.optionals.getOrNull
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope("prototype")
class AimeDbRequestHandler(
val cardService: CardService
): ChannelInboundHandlerAdapter() {
val logger: Logger = LoggerFactory.getLogger(AimeDbRequestHandler::class.java)
data class AimeBaseInfo(val gameId: String, val keychipId: String)
fun getBaseInfo(input: ByteBuf) = AimeBaseInfo(
gameId = input.toString(0x000a, 0x000e - 0x000a, StandardCharsets.US_ASCII),
keychipId = input.toString(0x0014, 0x001f - 0x0014, StandardCharsets.US_ASCII)
)
final val handlers = mapOf<Int, (ByteBuf) -> ByteBuf?>(
0x0001 to ::doFelicaLookup,
0x0004 to ::doLookup,
0x0005 to ::doRegister,
0x0009 to ::doLog,
0x000b to ::doCampaign,
0x000d to ::doTouch,
0x000f to ::doLookup2,
0x0011 to ::doFelicaLookup2,
0x0013 to ::doUnknown19,
0x0064 to ::doHello,
0x0066 to ::doGoodbye
)
/**
* Handle the incoming request
*/
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
if (msg is Map<*, *>) {
val type = msg["type"] as Int
val data = msg["data"] as ByteBuf
val base = getBaseInfo(data)
val handler = handlers[type] ?: let {
logger.error("AimeDB: Unknown request type: ${type.toString(16)}")
ctx.flush()
return
}
logger.info("AimeDB: Request $handler for game ${base.gameId}, from keychip ${base.keychipId}")
val result = handler(data)
if (result != null) ctx.writeAndFlush(result)
else ctx.flush()
}
}
@Deprecated("Deprecated in Netty 5") // TODO: Move this to ChannelInboundHandler
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
logger.error("AimeDB: Error", cause)
ctx.close()
}
override fun channelInactive(ctx: ChannelHandlerContext) {
super.channelInactive(ctx)
logger.debug("AimeDB: Connection closed")
}
/**
* Felica Lookup v1: Return the Felica IDm as-is
*/
fun doFelicaLookup(msg: ByteBuf): ByteBuf {
val idm = msg.slice(0x0020, 0x0028 - 0x0020).getLong(0)
val pmm = msg.slice(0x0028, 0x0030 - 0x0028).getLong(0)
logger.info("> Felica Lookup v1 ($idm, $pmm)")
// Get the decimal represent of the hex value, same from minime
val accessCode = idm.toString().replace("-", "").padStart(20, '0')
logger.info("> Response: $accessCode")
return Unpooled.copiedBuffer(ByteArray(0x0030)).apply {
setShortLE(0x0004, 0x0003)
setShortLE(0x0008, 1)
setBytes(0x0024, ByteBufUtil.decodeHexDump(accessCode))
}
}
/**
* Felica Lookup v2: Look up the card in the card repository, return the External ID
*/
fun doFelicaLookup2(msg: ByteBuf): ByteBuf {
val idm = msg.slice(0x0020, 0x0028 - 0x0020).getLong(0)
val pmm = msg.slice(0x0028, 0x0030 - 0x0028).getLong(0)
logger.info("> Felica Lookup v2 ($idm, $pmm)")
// Get the decimal represent of the hex value, same from minime
val accessCode = idm.toString().replace("-", "").padStart(20, '0')
val aimeId = cardService.getCardByAccessCode(accessCode).getOrNull()?.extId ?: -1
logger.info("Response: $accessCode, $aimeId")
return Unpooled.copiedBuffer(ByteArray(0x0140)).apply {
setShortLE(0x0004, 0x0012)
setShortLE(0x0008, 1)
setLongLE(0x0020, aimeId)
setIntLE(0x0024, -0x1) // 0xFFFFFFFF
setIntLE(0x0028, -0x1) // 0xFFFFFFFF
setBytes(0x002c, ByteBufUtil.decodeHexDump(accessCode))
setShortLE(0x0037, 0x0001)
}
}
/**
* Lookup v1: Find the LUID in the database and return the External ID
*/
fun doLookup(msg: ByteBuf): ByteBuf {
val luid = ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020))
logger.info("> Lookup v1 ($luid)")
val aimeId = cardService.getCardByAccessCode(luid).getOrNull()?.extId ?: -1
logger.info("> Response: $aimeId")
return Unpooled.copiedBuffer(ByteArray(0x0130)).apply {
setShortLE(0x0004, 0x0006)
setShortLE(0x0008, 1)
setLongLE(0x0020, aimeId)
setByte(0x0024, 0)
}
}
fun doLookup2(msg: ByteBuf): ByteBuf {
val luid = ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020))
logger.info("> Lookup v2 ($luid)")
val aimeId = cardService.getCardByAccessCode(luid).getOrNull()?.extId ?: -1
logger.info("Response: $aimeId")
return Unpooled.copiedBuffer(ByteArray(0x0130)).apply {
setShortLE(0x0004, 0x0010)
setShortLE(0x0008, 1)
setLongLE(0x0020, aimeId)
setByte(0x0024, 0)
}
}
/**
* Register: Register a new card by access code
*/
fun doRegister(msg: ByteBuf): ByteBuf {
val luid = ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020))
logger.info("> Register ($luid)")
var status = 0
var aimeId = 0L
if (cardService.getCardByAccessCode(luid).isEmpty) {
val card: Card = cardService.registerByAccessCode(luid)
status = 1
aimeId = card.extId
}
else logger.warn("> Duplicated Aime Card Register detected, access code: $luid")
logger.info("> Response: $status, $aimeId")
return Unpooled.copiedBuffer(ByteArray(0x0030)).apply {
setShortLE(0x0004, 0x0006)
setShortLE(0x0008, status)
setLongLE(0x0020, aimeId)
}
}
/**
* Log: Just log the request and return a status 1
*/
fun doLog(msg: ByteBuf) = Unpooled.copiedBuffer(ByteArray(0x0020)).apply {
setShortLE(0x0004, 0x000a)
setShortLE(0x0008, 1)
}
/**
* Campaign: Just return a status 1
*/
fun doCampaign(msg: ByteBuf) = Unpooled.copiedBuffer(ByteArray(0x0200)).apply {
setShortLE(0x0004, 0x000c)
setShortLE(0x0008, 1)
}
/**
* Touch: Just return a status 1
*/
fun doTouch(msg: ByteBuf): ByteBuf {
val aimeId = msg.getUnsignedIntLE(0x0020)
logger.info("> Touch ($aimeId)")
return Unpooled.copiedBuffer(ByteArray(0x0050)).apply {
setShortLE(0x0004, 0x000e)
setShortLE(0x0008, 1)
setShortLE(0x0020, 0x006f)
setShortLE(0x0024, 0x0001)
}
}
/**
* We don't know what this is, just return a status 1
*/
fun doUnknown19(msg: ByteBuf) = Unpooled.copiedBuffer(ByteArray(0x0040)).apply {
setShortLE(0x0004, 0x0014)
setShortLE(0x0008, 1)
}
/**
* Ping: Just return a status 1
*/
fun doHello(msg: ByteBuf) = Unpooled.copiedBuffer(ByteArray(0x0020)).apply {
setShortLE(0x0004, 0x0065)
setShortLE(0x0008, 1)
}
fun doGoodbye(msg: ByteBuf) = null
}

View File

@ -1,4 +1,4 @@
package icu.samnyan.aqua.sega.aimedb.exception;
package icu.samnyan.aqua.sega.aimedb;
/**
* @author samnyan (privateamusement@protonmail.com)

View File

@ -1,13 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public interface BaseHandler {
void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException;
}

View File

@ -1,53 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class CampaignHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(CampaignHandler.class);
private final LogMapper logMapper;
@Autowired
public CampaignHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "campaign");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "campaign");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0200]);
respSrc.setShortLE(0x0004, 0x000c);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,57 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil
import icu.samnyan.aqua.sega.aimedb.util.LogMapper
import icu.samnyan.aqua.sega.general.dao.CardRepository
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
class FeliCaLookup2Handler(
val logMapper: LogMapper,
val cardRepository: CardRepository
) : BaseHandler {
val logger: Logger = LoggerFactory.getLogger(FeliCaLookup2Handler::class.java)
override fun handle(ctx: ChannelHandlerContext, msg: ByteBuf) {
val requestMap = AimeDbUtil.getBaseInfo(msg)
requestMap["type"] = "felica_lookup2"
requestMap["idm"] = msg.slice(0x0030, 0x0038 - 0x0030)
requestMap["pmm"] = msg.slice(0x0038, 0x0040 - 0x0038)
logger.info("Request: " + logMapper.write(requestMap))
// Get the decimal represent of the hex value, same from minime
val accessCode = (requestMap["idm"] as ByteBuf).getLong(0).toString()
.replace("-", "") // Prevent negative overflow
.padStart(20, '0')
var aimeId: Long = -1
val card = cardRepository.findByLuid(accessCode)
if (card.isPresent) {
aimeId = card.get().extId
}
logger.info("Response: $accessCode, $aimeId")
val respSrc = Unpooled.copiedBuffer(ByteArray(0x0140))
respSrc.setShortLE(0x0004, 0x0012)
respSrc.setShortLE(0x0008, 1)
respSrc.setLongLE(0x0020, aimeId)
respSrc.setIntLE(0x0024, -0x1)
respSrc.setIntLE(0x0028, -0x1)
respSrc.setBytes(0x002c, ByteBufUtil.decodeHexDump(accessCode))
respSrc.setShortLE(0x0037, 0x0001)
ctx.writeAndFlush(respSrc)
}
}

View File

@ -1,44 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil
import icu.samnyan.aqua.sega.aimedb.util.LogMapper
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
class FeliCaLookupHandler(val logMapper: LogMapper) : BaseHandler {
val logger: Logger = LoggerFactory.getLogger(FeliCaLookupHandler::class.java)
override fun handle(ctx: ChannelHandlerContext, msg: ByteBuf) {
val requestMap = AimeDbUtil.getBaseInfo(msg)
requestMap["type"] = "felica_lookup"
requestMap["idm"] = msg.slice(0x0020, 0x0028 - 0x0020)
requestMap["pmm"] = msg.slice(0x0028, 0x0030 - 0x0028)
logger.info("Request: " + logMapper.write(requestMap))
// Get the decimal represent of the hex value, same from minime
val accessCode = (requestMap["idm"] as ByteBuf).getLong(0).toString()
.replace("-", "") // Prevent negative overflow
.padStart(20, '0')
logger.info("Response: $accessCode")
val respSrc = Unpooled.copiedBuffer(ByteArray(0x0030))
respSrc.setShortLE(0x0004, 0x0003)
respSrc.setShortLE(0x0008, 1)
respSrc.setBytes(0x0024, ByteBufUtil.decodeHexDump(accessCode))
ctx.writeAndFlush(respSrc)
}
}

View File

@ -1,32 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class GoodbyeHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(GoodbyeHandler.class);
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, String> requestMap = new HashMap<>();
requestMap.put("type", "goodbye");
logger.info("Request: " + new ObjectMapper().writeValueAsString(requestMap));
ctx.flush();
}
}

View File

@ -1,53 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class HelloHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(HelloHandler.class);
private final LogMapper logMapper;
@Autowired
public HelloHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "hello");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "hello");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0020]);
respSrc.setShortLE(0x0004, 0x0065);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,54 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class LogHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(LogHandler.class);
private final LogMapper logMapper;
@Autowired
public LogHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "log");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "log");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0020]);
respSrc.setShortLE(0x0004, 0x000a);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,48 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil.getBaseInfo
import icu.samnyan.aqua.sega.aimedb.util.LogMapper
import icu.samnyan.aqua.sega.general.dao.CardRepository
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
class Lookup2Handler(
val logMapper: LogMapper,
val cardRepository: CardRepository
) : BaseHandler {
val logger: Logger = LoggerFactory.getLogger(Lookup2Handler::class.java)
override fun handle(ctx: ChannelHandlerContext, msg: ByteBuf) {
val requestMap = getBaseInfo(msg)
requestMap["type"] = "lookup2"
requestMap["luid"] = ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020))
logger.info("Request: " + logMapper.write(requestMap))
var aimeId: Long = -1
val card = cardRepository.findByLuid(requestMap["luid"] as String?)
if (card.isPresent) {
aimeId = card.get().extId
}
logger.info("Response: $aimeId")
val respSrc = Unpooled.copiedBuffer(ByteArray(0x0130))
respSrc.setShortLE(0x0004, 0x0010)
respSrc.setShortLE(0x0008, 1)
respSrc.setLongLE(0x0020, aimeId)
respSrc.setByte(0x0024, 0)
ctx.writeAndFlush(respSrc)
}
}

View File

@ -1,50 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil.getBaseInfo
import icu.samnyan.aqua.sega.aimedb.util.LogMapper
import icu.samnyan.aqua.sega.general.dao.CardRepository
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
/**
* Mifare Card lookup? idk
*
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
class LookupHandler(
val logMapper: LogMapper,
val cardRepository: CardRepository
) : BaseHandler {
val logger: Logger = LoggerFactory.getLogger(LookupHandler::class.java)
override fun handle(ctx: ChannelHandlerContext, msg: ByteBuf) {
val requestMap = getBaseInfo(msg)
requestMap["type"] = "lookup"
requestMap["luid"] = ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020))
logger.info("Request: " + logMapper.write(requestMap))
var aimeId: Long = -1
val card = cardRepository.findByLuid(requestMap["luid"] as String?)
if (card.isPresent) {
aimeId = card.get().extId
}
logger.info("Response: $aimeId")
val respSrc = Unpooled.copiedBuffer(ByteArray(0x0130))
respSrc.setShortLE(0x0004, 0x0006)
respSrc.setShortLE(0x0008, 1)
respSrc.setLongLE(0x0020, aimeId)
respSrc.setByte(0x0024, 0)
ctx.writeAndFlush(respSrc)
}
}

View File

@ -1,71 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import icu.samnyan.aqua.sega.general.model.Card;
import icu.samnyan.aqua.sega.general.service.CardService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class RegisterHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(RegisterHandler.class);
private final LogMapper logMapper;
private final CardService cardService;
@Autowired
public RegisterHandler(LogMapper logMapper, CardService cardService) {
this.logMapper = logMapper;
this.cardService = cardService;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "register");
requestMap.put("luid", ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020)));
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "register");
if (cardService.getCardByAccessCode((String) requestMap.get("luid")).isEmpty()) {
Card card = cardService.registerByAccessCode((String) requestMap.get("luid"));
resultMap.put("status", 1);
resultMap.put("aimeId", card.getExtId());
} else {
logger.warn("Duplicated Aime Card Register detected, access code: {}", requestMap.get("luid"));
resultMap.put("status", 0);
resultMap.put("aimeId", 0L);
}
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0030]);
respSrc.setShortLE(0x0004, 0x0006);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
respSrc.setLongLE(0x0020, (long) resultMap.get("aimeId"));
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,56 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class TouchHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(TouchHandler.class);
private final LogMapper logMapper;
@Autowired
public TouchHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "touch");
requestMap.put("aimeId", msg.getUnsignedIntLE(0x0020));
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "touch");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0050]);
respSrc.setShortLE(0x0004, 0x000e);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
respSrc.setShortLE(0x0020, 0x006f);
respSrc.setShortLE(0x0024, 0x0001);
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,52 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class Unknown19Handler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(Unknown19Handler.class);
private final LogMapper logMapper;
@Autowired
public Unknown19Handler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "unknown19");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "unknown19");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0040]);
respSrc.setShortLE(0x0004, 0x0014);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@ -1,15 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.util
import io.netty.buffer.ByteBuf
import java.nio.charset.StandardCharsets
/**
* @author samnyan (privateamusement@protonmail.com)
*/
object AimeDbUtil {
@JvmStatic
fun getBaseInfo(input: ByteBuf) = mutableMapOf<String, Any>(
"gameId" to input.toString(0x000a, 0x000e - 0x000a, StandardCharsets.US_ASCII),
"keychipId" to input.toString(0x0014, 0x001f - 0x0014, StandardCharsets.US_ASCII)
)
}

View File

@ -1,28 +0,0 @@
package icu.samnyan.aqua.sega.aimedb.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import icu.samnyan.aqua.sega.util.jackson.ByteBufSerializer;
import io.netty.buffer.ByteBuf;
import org.springframework.stereotype.Component;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class LogMapper {
private final ObjectMapper mapper;
public LogMapper() {
mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(ByteBuf.class, new ByteBufSerializer());
mapper.registerModule(module);
}
public String write(Object o) throws JsonProcessingException {
return mapper.writeValueAsString(o);
}
}